diff --git a/apps/comments/lib/Search/CommentsSearchProvider.php b/apps/comments/lib/Search/CommentsSearchProvider.php index 3ce6abf306c55..81a05c7d37e70 100644 --- a/apps/comments/lib/Search/CommentsSearchProvider.php +++ b/apps/comments/lib/Search/CommentsSearchProvider.php @@ -53,10 +53,6 @@ public function getOrder(string $route, array $routeParameters): int { public function search(IUser $user, ISearchQuery $query): SearchResult { $userFolder = $this->rootFolder->getUserFolder($user->getUID()); - if ($userFolder === null) { - return SearchResult::complete($this->l10n->t('Comments'), []); - } - $result = []; $numComments = 50; $offset = 0; diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php index fe09c3f423fbb..ac69592f3af8f 100644 --- a/apps/dav/lib/Connector/Sabre/Directory.php +++ b/apps/dav/lib/Connector/Sabre/Directory.php @@ -7,7 +7,9 @@ */ namespace OCA\DAV\Connector\Sabre; +use OC\Files\Mount\DummyMountPoint; use OC\Files\Mount\MoveableMount; +use OC\Files\Storage\FailedStorage; use OC\Files\View; use OCA\DAV\AppInfo\Application; use OCA\DAV\Connector\Sabre\Exception\FileLocked; @@ -106,9 +108,9 @@ public function createFile($name, $data = null) { $info = $this->fileView->getFileInfo($this->path . '/' . $name); if (!$info) { // use a dummy FileInfo which is acceptable here since it will be refreshed after the put is complete - $info = new \OC\Files\FileInfo($path, null, null, [ + $info = new \OC\Files\FileInfo($path, new FailedStorage(['exception' => new \LogicException('Dummy storage') ]), '', [ 'type' => FileInfo::TYPE_FILE - ], null); + ], new DummyMountPoint()); } $node = new File($this->fileView, $info); diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php index d2a71eb3e7b8a..45ebd920100d7 100644 --- a/apps/dav/lib/Connector/Sabre/File.php +++ b/apps/dav/lib/Connector/Sabre/File.php @@ -54,12 +54,6 @@ class File extends Node implements IFile { /** * Sets up the node, expects a full path name - * - * @param View $view - * @param FileInfo $info - * @param ?\OCP\Share\IManager $shareManager - * @param ?IRequest $request - * @param ?IL10N $l10n */ public function __construct(View $view, FileInfo $info, ?IManager $shareManager = null, ?IRequest $request = null, ?IL10N $l10n = null) { parent::__construct($view, $info, $shareManager); @@ -368,7 +362,7 @@ public function put($data) { if ($checksumHeader) { $checksum = trim($checksumHeader); $this->setChecksum($checksum); - } elseif ($this->getChecksum() !== null && $this->getChecksum() !== '') { + } elseif ($this->getChecksum() !== '') { $this->setChecksum(''); } } catch (StorageNotAvailableException $e) { @@ -605,10 +599,8 @@ private function convertToSabreException(\Exception $e) { /** * Get the checksum for this file - * - * @return string|null */ - public function getChecksum() { + public function getChecksum(): string { return $this->info->getChecksum(); } diff --git a/apps/dav/lib/Connector/Sabre/FilesPlugin.php b/apps/dav/lib/Connector/Sabre/FilesPlugin.php index eed57ee0be8eb..bc6f03e8c1e71 100644 --- a/apps/dav/lib/Connector/Sabre/FilesPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesPlugin.php @@ -276,7 +276,7 @@ public function httpGet(RequestInterface $request, ResponseInterface $response) if ($node instanceof File) { //Add OC-Checksum header $checksum = $node->getChecksum(); - if ($checksum !== null && $checksum !== '') { + if ($checksum !== '') { $response->addHeader('OC-Checksum', $checksum); } } @@ -310,7 +310,7 @@ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) }); $propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function () use ($node) { - return $node->getInternalFileId(); + return (string)$node->getInternalFileId(); }); $propFind->handle(self::PERMISSIONS_PROPERTYNAME, function () use ($node) { @@ -487,7 +487,7 @@ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) $propFind->handle(self::CHECKSUMS_PROPERTYNAME, function () use ($node) { $checksum = $node->getChecksum(); - if ($checksum === null || $checksum === '') { + if ($checksum === '') { return null; } diff --git a/apps/dav/lib/Connector/Sabre/Node.php b/apps/dav/lib/Connector/Sabre/Node.php index 14ac7063ace4e..3babcbcafd6bb 100644 --- a/apps/dav/lib/Connector/Sabre/Node.php +++ b/apps/dav/lib/Connector/Sabre/Node.php @@ -27,18 +27,8 @@ abstract class Node implements \Sabre\DAV\INode { /** * The path to the current node - * - * @var string - */ - protected $path; - - protected FileInfo $info; - - /** - * @var IManager */ - protected $shareManager; - + protected string $path = ''; protected \OCP\Files\Node $node; /** @@ -46,14 +36,11 @@ abstract class Node implements \Sabre\DAV\INode { */ public function __construct( protected View $fileView, - FileInfo $info, - ?IManager $shareManager = null, + protected FileInfo $info, + protected ?IManager $shareManager = null, ) { $this->path = $this->fileView->getRelativePath($info->getPath()); - $this->info = $info; - if ($shareManager) { - $this->shareManager = $shareManager; - } else { + if (!$this->shareManager) { $this->shareManager = Server::get(\OCP\Share\IManager::class); } if ($info instanceof Folder || $info instanceof File) { @@ -141,7 +128,7 @@ public function setName($name) { public function getLastModified() { $timestamp = $this->info->getMtime(); if (!empty($timestamp)) { - return (int)$timestamp; + return $timestamp; } return $timestamp; } @@ -207,7 +194,7 @@ public function getSize(): int|float { * @return int */ public function getId() { - return $this->info->getId(); + return $this->info->getId() ?? -1; } /** @@ -221,11 +208,8 @@ public function getFileId() { return null; } - /** - * @return integer - */ - public function getInternalFileId() { - return $this->info->getId(); + public function getInternalFileId(): int { + return $this->info->getId() ?? -1; } public function getInternalPath(): string { diff --git a/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php b/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php index 421ee1bdc1276..bf761cb76428d 100644 --- a/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php @@ -21,6 +21,7 @@ use OCP\Files\ForbiddenException; use OCP\Files\InvalidPathException; use OCP\Files\Mount\IMountPoint; +use OCP\Files\Storage\IStorage; use OCP\Files\StorageNotAvailableException; use PHPUnit\Framework\MockObject\MockObject; use Test\Traits\UserTrait; @@ -68,6 +69,8 @@ protected function setUp(): void { parent::setUp(); $this->view = $this->createMock(View::class); + $this->view->method('getAbsolutePath')->willReturnArgument(0); + $this->info = $this->createMock(FileInfo::class); $this->info->method('isReadable') ->willReturn(true); @@ -102,7 +105,7 @@ public function testDeleteRootFolderFails(): void { ->willReturn(true); $this->view->expects($this->never()) ->method('rmdir'); - $dir = $this->getDir(); + $dir = $this->getDir('/'); $dir->delete(); } @@ -226,6 +229,8 @@ public function testGetChildrenNoPermission(): void { ->method('isReadable') ->willReturn(false); + $this->view->method('getRelativePath')->willReturnArgument(0); + $dir = new Directory($this->view, $info); $dir->getChildren(); } @@ -238,6 +243,8 @@ public function testGetChildNoPermission(): void { ->method('isReadable') ->willReturn(false); + $this->view->method('getRelativePath')->willReturnArgument(0); + $dir = new Directory($this->view, $this->info); $dir->getChild('test'); } @@ -250,6 +257,8 @@ public function testGetChildThrowStorageNotAvailableException(): void { ->method('getFileInfo') ->willThrowException(new StorageNotAvailableException()); + $this->view->method('getRelativePath')->willReturnArgument(0); + $dir = new Directory($this->view, $this->info); $dir->getChild('.'); } @@ -264,6 +273,8 @@ public function testGetChildThrowInvalidPath(): void { $this->view->expects($this->never()) ->method('getFileInfo'); + $this->view->method('getRelativePath')->willReturnArgument(0); + $dir = new Directory($this->view, $this->info); $dir->getChild('.'); } @@ -421,12 +432,12 @@ public static function moveSuccessProvider(): array { private function moveTest(string $source, string $destination, array $updatables, array $deletables): void { $view = new TestViewDirectory($updatables, $deletables); - $sourceInfo = new FileInfo($source, null, null, [ + $sourceInfo = new FileInfo($source, $this->createMock(IStorage::class), '', [ 'type' => FileInfo::TYPE_FOLDER, - ], null); - $targetInfo = new FileInfo(dirname($destination), null, null, [ + ], $this->createMock(IMountPoint::class)); + $targetInfo = new FileInfo(dirname($destination), $this->createMock(IStorage::class), '', [ 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $sourceNode = new Directory($view, $sourceInfo); $targetNode = $this->getMockBuilder(Directory::class) @@ -451,8 +462,8 @@ public function testFailingMove(): void { $view = new TestViewDirectory($updatables, $deletables); - $sourceInfo = new FileInfo($source, null, null, ['type' => FileInfo::TYPE_FOLDER], null); - $targetInfo = new FileInfo(dirname($destination), null, null, ['type' => FileInfo::TYPE_FOLDER], null); + $sourceInfo = new FileInfo($source, $this->createMock(IStorage::class), '', ['type' => FileInfo::TYPE_FOLDER], $this->createMock(IMountPoint::class)); + $targetInfo = new FileInfo(dirname($destination), $this->createMock(IStorage::class), '', ['type' => FileInfo::TYPE_FOLDER], $this->createMock(IMountPoint::class)); $sourceNode = new Directory($view, $sourceInfo); $targetNode = $this->getMockBuilder(Directory::class) diff --git a/apps/dav/tests/unit/Connector/Sabre/FileTest.php b/apps/dav/tests/unit/Connector/Sabre/FileTest.php index 60c8382e131aa..bba6027cd3b3d 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FileTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FileTest.php @@ -26,6 +26,7 @@ use OCP\Files\InvalidContentException; use OCP\Files\InvalidPathException; use OCP\Files\LockNotAcquiredException; +use OCP\Files\Mount\IMountPoint; use OCP\Files\NotPermittedException; use OCP\Files\Storage\IStorage; use OCP\Files\StorageNotAvailableException; @@ -184,10 +185,10 @@ function ($path) use ($storage) { ->method('getRelativePath') ->willReturnArgument(0); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); @@ -227,12 +228,12 @@ private function doPut(string $path, ?string $viewRoot = null, ?Request $request $info = new \OC\Files\FileInfo( $viewRoot . '/' . ltrim($path, '/'), $this->getMockStorage(), - null, + '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, ], - null + $this->createMock(IMountPoint::class), ); /** @var File&MockObject $file */ @@ -495,10 +496,10 @@ public function testSimplePutFailsSizeCheck(): void { 'method' => 'PUT', ], $this->requestId, $this->config, null); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info, null, $request); @@ -529,10 +530,10 @@ public function testSimplePutFailsMoveFromStorage(): void { // simulate situation where the target file is locked $view->lockFile('/test.txt', ILockingProvider::LOCK_EXCLUSIVE); - $info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); @@ -567,10 +568,10 @@ public function testSimplePutInvalidChars(): void { ->method('getRelativePath') ->willReturnArgument(0); - $info = new \OC\Files\FileInfo("/i\nvalid", $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo("/i\nvalid", $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); // action @@ -608,10 +609,10 @@ public function testSetNameInvalidChars(): void { ->method('getRelativePath') ->willReturnArgument(0); - $info = new \OC\Files\FileInfo('/valid', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/valid', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); $file->setName("/i\nvalid"); @@ -642,10 +643,10 @@ public function testUploadAbort(): void { 'method' => 'PUT', ], $this->requestId, $this->config, null); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info, null, $request); @@ -674,14 +675,17 @@ public function testDeleteWhenAllowed(): void { $view = $this->getMockBuilder(View::class) ->getMock(); + $view->method('getAbsolutePath')->willReturnArgument(0); + $view->method('getRelativePath')->willReturnArgument(0); + $view->expects($this->once()) ->method('unlink') ->willReturn(true); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); @@ -698,10 +702,13 @@ public function testDeleteThrowsWhenDeletionNotAllowed(): void { $view = $this->getMockBuilder(View::class) ->getMock(); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $view->method('getAbsolutePath')->willReturnArgument(0); + $view->method('getRelativePath')->willReturnArgument(0); + + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => 0, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); @@ -718,15 +725,18 @@ public function testDeleteThrowsWhenDeletionFailed(): void { $view = $this->getMockBuilder(View::class) ->getMock(); + $view->method('getAbsolutePath')->willReturnArgument(0); + $view->method('getRelativePath')->willReturnArgument(0); + // but fails $view->expects($this->once()) ->method('unlink') ->willReturn(false); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); @@ -743,15 +753,18 @@ public function testDeleteThrowsWhenDeletionThrows(): void { $view = $this->getMockBuilder(View::class) ->getMock(); + $view->method('getAbsolutePath')->willReturnArgument(0); + $view->method('getRelativePath')->willReturnArgument(0); + // but fails $view->expects($this->once()) ->method('unlink') ->willThrowException(new ForbiddenException('', true)); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); @@ -785,12 +798,12 @@ public function testPutLocking(): void { $info = new \OC\Files\FileInfo( '/' . $this->user . '/files/' . $path, $this->getMockStorage(), - null, + '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, ], - null + $this->createMock(IMountPoint::class) ); $file = new File($view, $info); @@ -921,10 +934,10 @@ public function testGetFopenFails(): void { ->method('fopen') ->willReturn(false); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FILE, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); @@ -943,10 +956,10 @@ public function testGetFopenThrows(): void { ->method('fopen') ->willThrowException(new ForbiddenException('', true)); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FILE, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); @@ -964,10 +977,10 @@ public function testGetThrowsIfNoPermission(): void { $view->expects($this->never()) ->method('fopen'); - $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ + $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), '', [ 'permissions' => Constants::PERMISSION_CREATE, // no read perm 'type' => FileInfo::TYPE_FOLDER, - ], null); + ], $this->createMock(IMountPoint::class)); $file = new File($view, $info); @@ -1012,12 +1025,12 @@ public function testPutLockExpired(): void { $info = new \OC\Files\FileInfo( '/' . $this->user . '/files/' . $path, $this->getMockStorage(), - null, + '', [ 'permissions' => Constants::PERMISSION_ALL, 'type' => FileInfo::TYPE_FOLDER, ], - null + $this->createMock(IMountPoint::class) ); $file = new File($view, $info); diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php index 4df3accfda95b..0023471d239a8 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php @@ -98,7 +98,7 @@ private function createTestNode(string $class, string $path = '/dummypath'): Moc ->willReturn('00000123instanceid'); $node->expects($this->any()) ->method('getInternalFileId') - ->willReturn('123'); + ->willReturn(123); $node->expects($this->any()) ->method('getEtag') ->willReturn('"abc"'); diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php index 176949f999c78..5b4ec68defe4e 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php @@ -57,6 +57,8 @@ protected function setUp(): void { $this->tree = $this->createMock(Tree::class); $this->view = $this->createMock(View::class); + $this->view->method('getAbsolutePath')->willReturnArgument(0); + $this->view->method('getRelativePath')->willReturnArgument(0); $this->server = $this->getMockBuilder(Server::class) ->setConstructorArgs([$this->tree]) @@ -315,14 +317,14 @@ public function testPrepareResponses(): void { $node1->expects($this->once()) ->method('getInternalFileId') - ->willReturn('111'); + ->willReturn(111); $node1->expects($this->any()) ->method('getPath') ->willReturn('/node1'); $node1->method('getFileInfo')->willReturn($fileInfo); $node2->expects($this->once()) ->method('getInternalFileId') - ->willReturn('222'); + ->willReturn(222); $node2->expects($this->once()) ->method('getSize') ->willReturn(1024); diff --git a/apps/dav/tests/unit/Connector/Sabre/NodeTest.php b/apps/dav/tests/unit/Connector/Sabre/NodeTest.php index 11970769a1e7b..abac73240a013 100644 --- a/apps/dav/tests/unit/Connector/Sabre/NodeTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/NodeTest.php @@ -55,7 +55,7 @@ public static function davPermissionsProvider(): array { public function testDavPermissions(int $permissions, string $type, bool $shared, int $shareRootPermissions, bool $mounted, string $internalPath, string $expected): void { $info = $this->getMockBuilder(FileInfo::class) ->disableOriginalConstructor() - ->onlyMethods(['getPermissions', 'isShared', 'isMounted', 'getType', 'getInternalPath', 'getStorage', 'getMountPoint']) + ->onlyMethods(['getPermissions', 'isShared', 'isMounted', 'getType', 'getPath', 'getInternalPath', 'getStorage', 'getMountPoint']) ->getMock(); $info->method('getPermissions') ->willReturn($permissions); @@ -65,6 +65,8 @@ public function testDavPermissions(int $permissions, string $type, bool $shared, ->willReturn($mounted); $info->method('getType') ->willReturn($type); + $info->method('getPath') + ->willReturn(''); $info->method('getInternalPath') ->willReturn($internalPath); $info->method('getMountPoint') @@ -94,8 +96,10 @@ public function testDavPermissions(int $permissions, string $type, bool $shared, $info->method('getStorage') ->willReturn($storage); $view = $this->createMock(View::class); + $view->method('getRelativePath')->willReturnArgument(0); + $view->method('getAbsolutePath')->willReturnArgument(0); - $node = new File($view, $info); + $node = new File($view, $info); $this->assertEquals($expected, $node->getDavPermissions()); } @@ -160,15 +164,18 @@ public function testSharePermissions(string $type, ?string $user, int $permissio $info = $this->getMockBuilder(FileInfo::class) ->disableOriginalConstructor() - ->onlyMethods(['getStorage', 'getType', 'getMountPoint', 'getPermissions']) + ->onlyMethods(['getStorage', 'getType', 'getPath', 'getMountPoint', 'getPermissions']) ->getMock(); $info->method('getStorage')->willReturn($storage); $info->method('getType')->willReturn($type); + $info->method('getPath')->willReturn(''); $info->method('getMountPoint')->willReturn($mountpoint); $info->method('getPermissions')->willReturn($permissions); $view = $this->createMock(View::class); + $view->method('getRelativePath')->willReturnArgument(0); + $view->method('getAbsolutePath')->willReturnArgument(0); $node = new File($view, $info); $this->invokePrivate($node, 'shareManager', [$shareManager]); @@ -196,14 +203,17 @@ public function testShareAttributes(): void { /** @var Folder&MockObject $info */ $info = $this->getMockBuilder(Folder::class) ->disableOriginalConstructor() - ->onlyMethods(['getStorage', 'getType']) + ->onlyMethods(['getStorage', 'getType', 'getPath']) ->getMock(); $info->method('getStorage')->willReturn($storage); $info->method('getType')->willReturn(FileInfo::TYPE_FOLDER); + $info->method('getPath')->willReturn(''); /** @var View&MockObject $view */ $view = $this->createMock(View::class); + $view->method('getRelativePath')->willReturnArgument(0); + $view->method('getAbsolutePath')->willReturnArgument(0); $node = new File($view, $info); $this->invokePrivate($node, 'shareManager', [$shareManager]); @@ -217,14 +227,17 @@ public function testShareAttributesNonShare(): void { /** @var Folder&MockObject */ $info = $this->getMockBuilder(Folder::class) ->disableOriginalConstructor() - ->onlyMethods(['getStorage', 'getType']) + ->onlyMethods(['getStorage', 'getType', 'getPath']) ->getMock(); $info->method('getStorage')->willReturn($storage); $info->method('getType')->willReturn(FileInfo::TYPE_FOLDER); + $info->method('getPath')->willReturn(''); /** @var View&MockObject */ $view = $this->createMock(View::class); + $view->method('getRelativePath')->willReturnArgument(0); + $view->method('getAbsolutePath')->willReturnArgument(0); $node = new File($view, $info); $this->invokePrivate($node, 'shareManager', [$shareManager]); @@ -243,6 +256,9 @@ public function testSanitizeMtime(string|int $mtime, int $expected): void { $view = $this->getMockBuilder(View::class) ->disableOriginalConstructor() ->getMock(); + $view->method('getAbsolutePath')->willReturnArgument(0); + $view->method('getRelativePath')->willReturnArgument(0); + $info = $this->getMockBuilder(FileInfo::class) ->disableOriginalConstructor() ->getMock(); @@ -263,6 +279,8 @@ public function testInvalidSanitizeMtime(int|string $mtime): void { $this->expectException(\InvalidArgumentException::class); $view = $this->createMock(View::class); + $view->method('getRelativePath')->willReturnArgument(0); + $view->method('getAbsolutePath')->willReturnArgument(0); $info = $this->createMock(FileInfo::class); $node = new File($view, $info); diff --git a/apps/dav/tests/unit/Connector/Sabre/ObjectTreeTest.php b/apps/dav/tests/unit/Connector/Sabre/ObjectTreeTest.php index b07778e4fbdac..1a9d621cc747a 100644 --- a/apps/dav/tests/unit/Connector/Sabre/ObjectTreeTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/ObjectTreeTest.php @@ -19,6 +19,7 @@ use OCA\DAV\Connector\Sabre\File; use OCA\DAV\Connector\Sabre\ObjectTree; use OCP\Files\Mount\IMountManager; +use PHPUnit\Framework\MockObject\MockObject; /** * Class ObjectTreeTest @@ -41,7 +42,7 @@ public static function copyDataProvider(): array { #[\PHPUnit\Framework\Attributes\DataProvider('copyDataProvider')] public function testCopy(string $sourcePath, string $targetPath, string $targetParent): void { - $view = $this->createMock(View::class); + $view = $this->createView(); $view->expects($this->once()) ->method('verifyPath') ->with($targetParent); @@ -85,7 +86,7 @@ public function testCopy(string $sourcePath, string $targetPath, string $targetP public function testCopyFailNotCreatable($sourcePath, $targetPath, $targetParent): void { $this->expectException(\Sabre\DAV\Exception\Forbidden::class); - $view = $this->createMock(View::class); + $view = $this->createView(); $view->expects($this->never()) ->method('verifyPath'); $view->expects($this->once()) @@ -129,7 +130,7 @@ public function testGetNodeForPath( ): void { $rootNode = $this->createMock(Directory::class); $mountManager = $this->createMock(Manager::class); - $view = $this->createMock(View::class); + $view = $this->createView(); $fileInfo = $this->createMock(FileInfo::class); $fileInfo->method('getType') ->willReturn($type); @@ -240,4 +241,11 @@ public function testGetNodeForPathRoot(): void { $this->assertInstanceOf('\Sabre\DAV\INode', $tree->getNodeForPath($path)); } + + private function createView(): View&MockObject { + $view = $this->createMock(View::class); + $view->method('getAbsolutePath')->willReturnArgument(0); + $view->method('getRelativePath')->willReturnArgument(0); + return $view; + } } diff --git a/apps/dav/tests/unit/Connector/Sabre/QuotaPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/QuotaPluginTest.php index 6fe2d6ccabe03..5b5b7df8f7be7 100644 --- a/apps/dav/tests/unit/Connector/Sabre/QuotaPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/QuotaPluginTest.php @@ -19,7 +19,7 @@ class QuotaPluginTest extends TestCase { private QuotaPlugin $plugin; private function init(int $quota, string $checkedPath = ''): void { - $view = $this->buildFileViewMock((string)$quota, $checkedPath); + $view = $this->buildFileViewMock($quota, $checkedPath); $this->server = new \Sabre\DAV\Server(); $this->plugin = new QuotaPlugin($view); $this->plugin->initialize($this->server); @@ -136,7 +136,7 @@ public static function quotaChunkedFailProvider(): array { ]; } - private function buildFileViewMock(string $quota, string $checkedPath): View { + private function buildFileViewMock(int $quota, string $checkedPath): View { // mock filesystem $view = $this->getMockBuilder(View::class) ->onlyMethods(['free_space']) diff --git a/apps/dav/tests/unit/Connector/Sabre/RequestTest/RequestTestCase.php b/apps/dav/tests/unit/Connector/Sabre/RequestTest/RequestTestCase.php index 404dc7fa5d7b4..d623cec705fd9 100644 --- a/apps/dav/tests/unit/Connector/Sabre/RequestTest/RequestTestCase.php +++ b/apps/dav/tests/unit/Connector/Sabre/RequestTest/RequestTestCase.php @@ -118,7 +118,7 @@ protected function makeRequest(Server $server, Request $request) { $sapi = new Sapi($request); $server->sapi = $sapi; $server->httpRequest = $request; - $server->exec(); + $server->start(); return $sapi->getResponse(); } diff --git a/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php b/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php index eefbc53fd22cb..66f69315590a4 100644 --- a/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php +++ b/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php @@ -97,6 +97,7 @@ public static function providesDataForCanGet(): array { #[\PHPUnit\Framework\Attributes\DataProvider('providesDataForCanGet')] public function testCanGet(bool $isVersion, ?bool $attrEnabled, bool $expectCanDownloadFile, bool $allowViewWithoutDownload): void { $nodeInfo = $this->createMock(File::class); + $nodeInfo->method('getId')->willReturn(42); if ($isVersion) { $davPath = 'versions/alice/versions/117/123456'; $version = $this->createMock(IVersion::class); diff --git a/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php b/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php index 1ce639532e842..62f8b14d2a2e8 100644 --- a/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php +++ b/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php @@ -338,7 +338,7 @@ private function shareAccepted($id, array $notification) { */ protected function executeAcceptShare(IShare $share) { try { - $fileId = (int)$share->getNode()->getId(); + $fileId = $share->getNode()->getId() ?? -1; [$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId); } catch (\Exception $e) { throw new ShareNotFound(); @@ -414,7 +414,7 @@ protected function executeDeclineShare(IShare $share) { $this->federatedShareProvider->removeShareFromTable($share); try { - $fileId = (int)$share->getNode()->getId(); + $fileId = $share->getNode()->getId() ?? -1; [$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId); } catch (\Exception $e) { throw new ShareNotFound(); diff --git a/apps/files/lib/Controller/ApiController.php b/apps/files/lib/Controller/ApiController.php index 8bb024fb69839..747d88d7b2671 100644 --- a/apps/files/lib/Controller/ApiController.php +++ b/apps/files/lib/Controller/ApiController.php @@ -202,9 +202,7 @@ private function getShareTypesForNodes(array $nodes): array { ]; $shareTypes = []; - $nodeIds = array_map(function (Node $node) { - return $node->getId(); - }, $nodes); + $nodeIds = array_filter(array_map(fn (Node $node): ?int => $node->getId(), $nodes)); foreach ($requestedShareTypes as $shareType) { $nodesLeft = array_combine($nodeIds, array_fill(0, count($nodeIds), true)); diff --git a/apps/files/lib/Controller/ConversionApiController.php b/apps/files/lib/Controller/ConversionApiController.php index 40a42d6ca4c8f..27fee6c318cfd 100644 --- a/apps/files/lib/Controller/ConversionApiController.php +++ b/apps/files/lib/Controller/ConversionApiController.php @@ -99,7 +99,7 @@ public function convert(int $fileId, string $targetMimeType, ?string $destinatio } $file = $userFolder->get($convertedFileRelativePath); - $fileId = $file->getId(); + $fileId = $file->getId() ?? -1; return new DataResponse([ 'path' => $convertedFileRelativePath, diff --git a/apps/files/lib/Listener/SyncLivePhotosListener.php b/apps/files/lib/Listener/SyncLivePhotosListener.php index b6773e8c45239..3cc9316ef776a 100644 --- a/apps/files/lib/Listener/SyncLivePhotosListener.php +++ b/apps/files/lib/Listener/SyncLivePhotosListener.php @@ -134,14 +134,14 @@ private function handleMove(Node $sourceFile, Node $targetFile, Node $peerFile): return; } - $this->pendingRenames[] = $sourceFile->getId(); + $this->pendingRenames[] = $sourceFile->getId() ?? -1; try { $peerFile->move($targetParent->getPath() . '/' . $peerTargetName); } catch (\Throwable $ex) { throw new AbortedEventException($ex->getMessage()); } - $this->pendingRenames = array_diff($this->pendingRenames, [$sourceFile->getId()]); + $this->pendingRenames = array_diff($this->pendingRenames, [$sourceFile->getId() ?? -1]); } @@ -185,14 +185,14 @@ private function handleCopy(File $sourceFile, File $targetFile, File $peerFile): private function handleDeletion(BeforeNodeDeletedEvent $event, Node $peerFile): void { $deletedFile = $event->getNode(); if ($deletedFile->getMimetype() === 'video/quicktime') { - if (isset($this->pendingDeletion[$peerFile->getId()])) { - unset($this->pendingDeletion[$peerFile->getId()]); + if (isset($this->pendingDeletion[$peerFile->getId() ?? -1])) { + unset($this->pendingDeletion[$peerFile->getId() ?? -1]); return; } else { throw new AbortedEventException('Cannot delete the video part of a live photo'); } } else { - $this->pendingDeletion[$deletedFile->getId()] = true; + $this->pendingDeletion[$deletedFile->getId() ?? -1] = true; try { $peerFile->delete(); } catch (\Throwable $ex) { diff --git a/apps/files/lib/Service/TagService.php b/apps/files/lib/Service/TagService.php index 95176ce95fae0..92b97538ef2f7 100644 --- a/apps/files/lib/Service/TagService.php +++ b/apps/files/lib/Service/TagService.php @@ -45,6 +45,9 @@ public function updateFileTags($path, $tags) { } $fileId = $this->homeFolder->get($path)->getId(); + if ($fileId === null) { + return []; + } $currentTags = $this->tagger->getTagsForObjects([$fileId]); diff --git a/apps/files/tests/Controller/ConversionApiControllerTest.php b/apps/files/tests/Controller/ConversionApiControllerTest.php index 659fbe1a9560d..5d6f0bc3c381c 100644 --- a/apps/files/tests/Controller/ConversionApiControllerTest.php +++ b/apps/files/tests/Controller/ConversionApiControllerTest.php @@ -43,6 +43,7 @@ protected function setUp(): void { $this->request = $this->createMock(IRequest::class); $this->fileConversionManager = $this->createMock(IConversionManager::class); $this->file = $this->createMock(File::class); + $this->file->method('isReadable')->willReturn(true); $this->l10n = $this->createMock(IL10N::class); $this->user = 'userid'; diff --git a/apps/files/tests/HelperTest.php b/apps/files/tests/HelperTest.php index ba93fa0efdf26..1ce279fcfbad3 100644 --- a/apps/files/tests/HelperTest.php +++ b/apps/files/tests/HelperTest.php @@ -9,12 +9,14 @@ use OC\Files\FileInfo; use OCA\Files\Helper; +use OCP\Files\Mount\IMountPoint; +use OCP\Files\Storage\IStorage; class HelperTest extends \Test\TestCase { - private static function makeFileInfo($name, $size, $mtime, $isDir = false): FileInfo { + private function makeFileInfo($name, $size, $mtime, $isDir = false): FileInfo { return new FileInfo( '/' . $name, - null, + $this->createMock(IStorage::class), '/', [ 'name' => $name, @@ -23,21 +25,21 @@ private static function makeFileInfo($name, $size, $mtime, $isDir = false): File 'type' => $isDir ? 'dir' : 'file', 'mimetype' => $isDir ? 'httpd/unix-directory' : 'application/octet-stream' ], - null + $this->createMock(IMountPoint::class), ); } /** * Returns a file list for testing */ - private static function getTestFileList(): array { + private function getTestFileList(): array { return [ - self::makeFileInfo('a.txt', 4, 2.3 * pow(10, 9)), - self::makeFileInfo('q.txt', 5, 150), - self::makeFileInfo('subdir2', 87, 128, true), - self::makeFileInfo('b.txt', 2.2 * pow(10, 9), 800), - self::makeFileInfo('o.txt', 12, 100), - self::makeFileInfo('subdir', 88, 125, true), + $this->makeFileInfo('a.txt', 4, 2.3 * pow(10, 9)), + $this->makeFileInfo('q.txt', 5, 150), + $this->makeFileInfo('subdir2', 87, 128, true), + $this->makeFileInfo('b.txt', 2.2 * pow(10, 9), 800), + $this->makeFileInfo('o.txt', 12, 100), + $this->makeFileInfo('subdir', 88, 125, true), ]; } @@ -81,7 +83,7 @@ public function testSortByName(string $sort, bool $sortDescending, array $expect if (($sort === 'mtime') && (PHP_INT_SIZE < 8)) { $this->markTestSkipped('Skip mtime sorting on 32bit'); } - $files = self::getTestFileList(); + $files = $this->getTestFileList(); $files = Helper::sortFiles($files, $sort, $sortDescending); $fileNames = []; foreach ($files as $fileInfo) { diff --git a/apps/files_sharing/lib/Command/ListShares.php b/apps/files_sharing/lib/Command/ListShares.php index 2d5cdbf78129b..3c2e53ca58b3d 100644 --- a/apps/files_sharing/lib/Command/ListShares.php +++ b/apps/files_sharing/lib/Command/ListShares.php @@ -90,7 +90,7 @@ private function getFileId(string $file): int { if (is_numeric($file)) { return (int)$file; } - return $this->getFile($file)->getId(); + return $this->getFile($file)->getId() ?? -1; } private function getFile(string $file): Node { diff --git a/apps/files_sharing/lib/Controller/DeletedShareAPIController.php b/apps/files_sharing/lib/Controller/DeletedShareAPIController.php index 2fa4d7c668f50..cbfd35cc2899b 100644 --- a/apps/files_sharing/lib/Controller/DeletedShareAPIController.php +++ b/apps/files_sharing/lib/Controller/DeletedShareAPIController.php @@ -73,7 +73,7 @@ private function formatShare(IShare $share): array { if (!$node) { // fallback to guessing the path $node = $userFolder->get($share->getTarget()); - if ($node === null || $share->getTarget() === '') { + if ($share->getTarget() === '') { throw new NotFoundException(); } } diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index 1520ef2e61ff6..889a18549b429 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -157,7 +157,7 @@ protected function formatShare(IShare $share, ?Node $recipientNode = null): arra if (!$node) { // fallback to guessing the path $node = $userFolder->get($share->getTarget()); - if ($node === null || $share->getTarget() === '') { + if ($share->getTarget() === '') { throw new NotFoundException(); } } @@ -200,9 +200,9 @@ protected function formatShare(IShare $share, ?Node $recipientNode = null): arra $result['has_preview'] = $this->previewManager->isAvailable($node); $result['storage_id'] = $node->getStorage()->getId(); $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId(); - $result['item_source'] = $node->getId(); - $result['file_source'] = $node->getId(); - $result['file_parent'] = $node->getParent()->getId(); + $result['item_source'] = $node->getId() ?? -1; + $result['file_source'] = $node->getId() ?? -1; + $result['file_parent'] = $node->getParent()->getId() ?? -1; $result['file_target'] = $share->getTarget(); $result['item_size'] = $node->getSize(); $result['item_mtime'] = $node->getMTime(); @@ -1452,7 +1452,7 @@ public function pendingShares(): DataResponse { if (!$node) { // fallback to guessing the path $node = $userFolder->get($share->getTarget()); - if ($node === null || $share->getTarget() === '') { + if ($share->getTarget() === '') { return null; } } diff --git a/apps/files_sharing/lib/Controller/ShareInfoController.php b/apps/files_sharing/lib/Controller/ShareInfoController.php index b7e79aec8304a..782eda2d2e663 100644 --- a/apps/files_sharing/lib/Controller/ShareInfoController.php +++ b/apps/files_sharing/lib/Controller/ShareInfoController.php @@ -138,8 +138,8 @@ private function parseFolder(Folder $folder, int $permissionMask, int $depth): a private function format(Node $node, int $permissionMask): array { $entry = []; - $entry['id'] = $node->getId(); - $entry['parentId'] = $node->getParent()->getId(); + $entry['id'] = $node->getId() ?? -1; + $entry['parentId'] = $node->getParent()->getId() ?? -1; $entry['mtime'] = $node->getMTime(); $entry['name'] = $node->getName(); diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index 93ce63c10209b..f8352369edb8a 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -519,7 +519,7 @@ public function testDeleteSharedWithGroupIDontBelongTo(): void { public function testDeleteShareOwnerless(): void { $ocs = $this->mockFormatShare(); - $mount = $this->createMock(IShareOwnerlessMount::class); + $mount = $this->createMockForIntersectionOfInterfaces([IShareOwnerlessMount::class, IMountPoint::class]); $file = $this->createMock(File::class); $file @@ -606,7 +606,7 @@ public function createShare( ?string $password = null, string $label = '', ?IShareAttributes $attributes = null, - ): MockObject { + ): IShare&MockObject { $share = $this->createMock(IShare::class); $share->method('getId')->willReturn($id); $share->method('getShareType')->willReturn($shareType); @@ -852,6 +852,7 @@ public function testGetShare(array $shareParams, array $result, bool $attributes $mountPoint->method('getMountType')->willReturn(''); $nodeParams = $shareParams[5]; + /** @var \OCP\Files\Node&MockObject $node */ $node = $this->createMock($nodeParams['class']); $node->method('getId')->willReturn($nodeParams['id']); $node->method('getPath')->willReturn($nodeParams['path']); @@ -860,7 +861,7 @@ public function testGetShare(array $shareParams, array $result, bool $attributes $node->method('getSize')->willReturn(123465); $node->method('getMTime')->willReturn(1234567890); $node->method('getMimeType')->willReturn($nodeParams['mimeType']); - $node->method('getMountPoint')->willReturn($mountPoint); + $node->method('getInternalPath')->willReturn(ltrim($nodeParams['path'], '/')); $shareParams[5] = $node; @@ -4008,7 +4009,7 @@ public function testUpdateShareCanIncreasePermissionsIfOwner(): void { public function testUpdateShareOwnerless(): void { $ocs = $this->mockFormatShare(); - $mount = $this->createMock(IShareOwnerlessMount::class); + $mount = $this->createMockForIntersectionOfInterfaces([IShareOwnerlessMount::class, IMountPoint::class]); $file = $this->createMock(File::class); $file @@ -4939,6 +4940,7 @@ function ($user) { $expects['attributes'] = \json_encode($shareParams['attributes']); } if (isset($shareParams['node'])) { + /** @var MockObject&\OCP\Files\Node $node */ $node = $this->createMock($shareParams['node']['class']); $node->method('getMimeType')->willReturn($shareParams['node']['mimeType']); @@ -4948,6 +4950,7 @@ function ($user) { $node->method('getMountPoint')->willReturn($mountPoint); $node->method('getPath')->willReturn($shareParams['node']['path']); + $node->method('getInternalPath')->willReturn(ltrim($shareParams['node']['path'], '/')); $node->method('getId')->willReturn($shareParams['node']['id']); $parent = $this->createMock(Folder::class); @@ -5166,6 +5169,7 @@ public function testFormatRoomShare(array $expects, bool $helperAvailable, array $file->method('getSize')->willReturn(123456); $file->method('getMTime')->willReturn(1234567890); + $file->method('getInternalPath')->willReturn(ltrim('file', '/')); $mountPoint = $this->createMock(IMountPoint::class); $mountPoint->method('getMountType')->willReturn(''); diff --git a/apps/files_trashbin/lib/Listeners/SyncLivePhotosListener.php b/apps/files_trashbin/lib/Listeners/SyncLivePhotosListener.php index 2cb3a94aa1dc8..e99b28c284c24 100644 --- a/apps/files_trashbin/lib/Listeners/SyncLivePhotosListener.php +++ b/apps/files_trashbin/lib/Listeners/SyncLivePhotosListener.php @@ -72,8 +72,8 @@ private function handleRestore(BeforeNodeRestoredEvent $event, Node $peerFile): $sourceFile = $event->getSource(); if ($sourceFile->getMimetype() === 'video/quicktime') { - if (isset($this->pendingRestores[$peerFile->getId()])) { - unset($this->pendingRestores[$peerFile->getId()]); + if (isset($this->pendingRestores[$peerFile->getId() ?? -1])) { + unset($this->pendingRestores[$peerFile->getId() ?? -1]); return; } else { $event->abortOperation(new NotPermittedException('Cannot restore the video part of a live photo')); @@ -97,7 +97,7 @@ private function handleRestore(BeforeNodeRestoredEvent $event, Node $peerFile): $event->abortOperation(new NotFoundException("Couldn't find peer file in trashbin")); } - $this->pendingRestores[$sourceFile->getId()] = true; + $this->pendingRestores[$sourceFile->getId() ?? -1] = true; try { $this->trashManager->restoreItem($trashItem); } catch (\Throwable $ex) { diff --git a/apps/files_trashbin/lib/Sabre/AbstractTrash.php b/apps/files_trashbin/lib/Sabre/AbstractTrash.php index f032395437b9b..9e750ab15d752 100644 --- a/apps/files_trashbin/lib/Sabre/AbstractTrash.php +++ b/apps/files_trashbin/lib/Sabre/AbstractTrash.php @@ -31,7 +31,7 @@ public function getDeletionTime(): int { } public function getFileId(): int { - return $this->data->getId(); + return $this->data->getId() ?? -1; } public function getFileInfo(): FileInfo { diff --git a/apps/files_trashbin/lib/Trash/TrashItem.php b/apps/files_trashbin/lib/Trash/TrashItem.php index 70d5164747f0b..de824adc30ab3 100644 --- a/apps/files_trashbin/lib/Trash/TrashItem.php +++ b/apps/files_trashbin/lib/Trash/TrashItem.php @@ -7,7 +7,10 @@ namespace OCA\Files_Trashbin\Trash; use OCP\Files\FileInfo; +use OCP\Files\Mount\IMountPoint; +use OCP\Files\Storage\IStorage; use OCP\IUser; +use Override; class TrashItem implements ITrashItem { @@ -46,126 +49,150 @@ public function getUser(): IUser { return $this->user; } - public function getEtag() { + public function getDeletedBy(): ?IUser { + return $this->deletedBy; + } + + #[Override] + public function getEtag(): string { return $this->fileInfo->getEtag(); } - public function getSize($includeMounts = true) { + #[Override] + public function getSize(bool $includeMounts = true): int|float { return $this->fileInfo->getSize($includeMounts); } - public function getMtime() { + #[Override] + public function getMtime(): int { return $this->fileInfo->getMtime(); } - public function getName() { + #[Override] + public function getName(): string { return $this->fileInfo->getName(); } - public function getInternalPath() { + #[Override] + public function getInternalPath(): string { return $this->fileInfo->getInternalPath(); } - public function getPath() { + #[Override] + public function getPath(): string { return $this->fileInfo->getPath(); } + #[Override] public function getMimetype(): string { return $this->fileInfo->getMimetype(); } - public function getMimePart() { + #[Override] + public function getMimePart(): string { return $this->fileInfo->getMimePart(); } - public function getStorage() { + #[Override] + public function getStorage(): IStorage { return $this->fileInfo->getStorage(); } - public function getId() { + #[Override] + public function getId(): ?int { return $this->fileInfo->getId(); } - public function isEncrypted() { + #[Override] + public function isEncrypted(): bool { return $this->fileInfo->isEncrypted(); } - public function getPermissions() { + #[Override] + public function getPermissions(): int { return $this->fileInfo->getPermissions(); } - public function getType() { + #[Override] + public function getType(): string { return $this->fileInfo->getType(); } - public function isReadable() { + #[Override] + public function isReadable(): bool { return $this->fileInfo->isReadable(); } - public function isUpdateable() { + #[Override] + public function isUpdateable(): bool { return $this->fileInfo->isUpdateable(); } - public function isCreatable() { + #[Override] + public function isCreatable(): bool { return $this->fileInfo->isCreatable(); } - public function isDeletable() { + #[Override] + public function isDeletable(): bool { return $this->fileInfo->isDeletable(); } - public function isShareable() { + public function isShareable(): bool { return $this->fileInfo->isShareable(); } - public function isShared() { + #[Override] + public function isShared(): bool { return $this->fileInfo->isShared(); } - public function isMounted() { + #[Override] + public function isMounted(): bool { return $this->fileInfo->isMounted(); } - public function getMountPoint() { + #[Override] + public function getMountPoint(): IMountPoint { return $this->fileInfo->getMountPoint(); } - public function getOwner() { + #[Override] + public function getOwner(): ?IUser { return $this->fileInfo->getOwner(); } - public function getChecksum() { + #[Override] + public function getChecksum(): string { return $this->fileInfo->getChecksum(); } + #[Override] public function getExtension(): string { return $this->fileInfo->getExtension(); } + #[Override] public function getTitle(): string { return $this->getOriginalLocation(); } + #[Override] public function getCreationTime(): int { return $this->fileInfo->getCreationTime(); } + #[Override] public function getUploadTime(): int { return $this->fileInfo->getUploadTime(); } + #[Override] public function getParentId(): int { return $this->fileInfo->getParentId(); } - public function getDeletedBy(): ?IUser { - return $this->deletedBy; - } - - /** - * @inheritDoc - * @return array - */ + #[Override] public function getMetadata(): array { return $this->fileInfo->getMetadata(); } diff --git a/apps/files_versions/lib/Listener/FileEventsListener.php b/apps/files_versions/lib/Listener/FileEventsListener.php index c200db7a83d48..77cf3881c111b 100644 --- a/apps/files_versions/lib/Listener/FileEventsListener.php +++ b/apps/files_versions/lib/Listener/FileEventsListener.php @@ -122,7 +122,7 @@ public function pre_touch_hook(Node $node): void { return; } - $this->nodesTouched[$node->getId()] = $node; + $this->nodesTouched[$node->getId() ?? -1] = $node; } public function touch_hook(Node $node): void { @@ -209,7 +209,7 @@ public function write_hook(Node $node): void { $result = Storage::store($path); // Store the result of the version creation so it can be used in post_write_hook. - $this->writeHookInfo[$node->getId()] = [ + $this->writeHookInfo[$node->getId() ?? -1] = [ 'previousNode' => $node, 'versionCreated' => $result !== false ]; diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php index 6d53a19a518e4..80194f12ce7f0 100644 --- a/apps/files_versions/lib/Storage.php +++ b/apps/files_versions/lib/Storage.php @@ -885,16 +885,16 @@ public static function expire($filename, $uid) { if ($quota >= 0) { if ($softQuota) { $root = Server::get(IRootFolder::class); - $userFolder = $root->getUserFolder($uid); - if (is_null($userFolder)) { - $availableSpace = 0; - } else { + try { + $userFolder = $root->getUserFolder($uid); $free = $quota - $userFolder->getSize(false); // remaining free space for user if ($free > 0) { $availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $versionsSize; // how much space can be used for versions } else { $availableSpace = $free - $versionsSize; } + } catch (NoUserException $e) { + $availableSpace = 0; } } else { $availableSpace = $quota; diff --git a/apps/files_versions/lib/Versions/LegacyVersionsBackend.php b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php index c2d57ae96f2b4..f7fb11cdb22e5 100644 --- a/apps/files_versions/lib/Versions/LegacyVersionsBackend.php +++ b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php @@ -57,7 +57,7 @@ public function getVersionsForFile(IUser $user, FileInfo $file): array { $user = $this->userManager->get($owner); $fileId = $file->getId(); - if ($fileId === null) { + if ($fileId === -1) { throw new NotFoundException("File not found ($fileId)"); } @@ -77,7 +77,7 @@ public function getVersionsForFile(IUser $user, FileInfo $file): array { } $fileId = $file->getId(); - if ($fileId === null) { + if ($fileId === -1) { throw new NotFoundException("File not found ($fileId)"); } diff --git a/apps/systemtags/lib/Activity/Listener.php b/apps/systemtags/lib/Activity/Listener.php index 93e3f102c94b9..d090198c62c1c 100644 --- a/apps/systemtags/lib/Activity/Listener.php +++ b/apps/systemtags/lib/Activity/Listener.php @@ -136,7 +136,7 @@ public function mapperEvent(MapperEvent $event) { foreach ($mounts as $mount) { $owner = $mount->getUser()->getUID(); $ownerFolder = $this->rootFolder->getUserFolder($owner); - $nodes = $ownerFolder->getById($event->getObjectId()); + $nodes = $ownerFolder->getById((int)$event->getObjectId()); if (!empty($nodes)) { /** @var Node $node */ $node = array_shift($nodes); diff --git a/apps/workflowengine/lib/Entity/File.php b/apps/workflowengine/lib/Entity/File.php index 6e85af2143277..da630ec103e83 100644 --- a/apps/workflowengine/lib/Entity/File.php +++ b/apps/workflowengine/lib/Entity/File.php @@ -136,9 +136,9 @@ protected function getNode(): Node { if (!$this->event instanceof MapperEvent || $this->event->getObjectType() !== 'files') { throw new NotFoundException(); } - $nodes = $this->root->getById((int)$this->event->getObjectId()); - if (is_array($nodes) && isset($nodes[0])) { - $this->node = $nodes[0]; + $node = $this->root->getFirstNodeById((int)$this->event->getObjectId()); + if ($node !== null) { + $this->node = $node; return $this->node; } break; diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 422d886658ad4..28f8aae1ff627 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -621,11 +621,6 @@ - - - - - @@ -697,14 +692,6 @@ - - - - - - info->getId()]]> - info->getId()]]> - @@ -1873,14 +1860,6 @@ - - - - - - data->getId()]]> - - @@ -3803,44 +3782,11 @@ - - - getStorage()]]> - findByNumericId($id)]]> - findByStorageId($id)]]> - - - - - - - - - - view->hash($type, $this->path, $raw)]]> - - - - - - - - createNode($file->getPath(), $file); - }, $files)]]> - - - - - - - - @@ -3858,64 +3804,6 @@ - - - __call(__FUNCTION__, func_get_args())]]> - - - - - - - - - - - - - - - - - - - parent]]> - - - - - - fileInfo]]> - - - - - - fileInfo]]> - fileInfo]]> - - - - - - mountManager->findByNumericId($numericId)]]> - mountManager->findByStorageId($storageId)]]> - mountManager->findIn($mountPoint)]]> - user]]> - - - - - - - - - user]]> - - - - - diff --git a/lib/composer/composer/LICENSE b/lib/composer/composer/LICENSE index f27399a042d95..62ecfd8d0046b 100644 --- a/lib/composer/composer/LICENSE +++ b/lib/composer/composer/LICENSE @@ -1,4 +1,3 @@ - Copyright (c) Nils Adermann, Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy @@ -18,4 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index add490d2b0681..41f38d1866264 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -1678,6 +1678,7 @@ 'OC\\Files\\Filesystem' => $baseDir . '/lib/private/Files/Filesystem.php', 'OC\\Files\\Lock\\LockManager' => $baseDir . '/lib/private/Files/Lock/LockManager.php', 'OC\\Files\\Mount\\CacheMountProvider' => $baseDir . '/lib/private/Files/Mount/CacheMountProvider.php', + 'OC\\Files\\Mount\\DummyMountPoint' => $baseDir . '/lib/private/Files/Mount/DummyMountPoint.php', 'OC\\Files\\Mount\\HomeMountPoint' => $baseDir . '/lib/private/Files/Mount/HomeMountPoint.php', 'OC\\Files\\Mount\\LocalHomeMountProvider' => $baseDir . '/lib/private/Files/Mount/LocalHomeMountProvider.php', 'OC\\Files\\Mount\\Manager' => $baseDir . '/lib/private/Files/Mount/Manager.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 6c6507f8b22a0..89c2d6a519c67 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -1719,6 +1719,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Files\\Filesystem' => __DIR__ . '/../../..' . '/lib/private/Files/Filesystem.php', 'OC\\Files\\Lock\\LockManager' => __DIR__ . '/../../..' . '/lib/private/Files/Lock/LockManager.php', 'OC\\Files\\Mount\\CacheMountProvider' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/CacheMountProvider.php', + 'OC\\Files\\Mount\\DummyMountPoint' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/DummyMountPoint.php', 'OC\\Files\\Mount\\HomeMountPoint' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/HomeMountPoint.php', 'OC\\Files\\Mount\\LocalHomeMountProvider' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/LocalHomeMountProvider.php', 'OC\\Files\\Mount\\Manager' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/Manager.php', diff --git a/lib/private/Files/AppData/AppData.php b/lib/private/Files/AppData/AppData.php index c13372ae1d9e7..dc303baa7947e 100644 --- a/lib/private/Files/AppData/AppData.php +++ b/lib/private/Files/AppData/AppData.php @@ -149,6 +149,6 @@ public function getDirectoryListing(): array { } public function getId(): int { - return $this->getAppDataFolder()->getId(); + return $this->getAppDataFolder()->getId() ?? -1; } } diff --git a/lib/private/Files/FileInfo.php b/lib/private/Files/FileInfo.php index 967d404b8a4f0..92ca241f84e7f 100644 --- a/lib/private/Files/FileInfo.php +++ b/lib/private/Files/FileInfo.php @@ -12,61 +12,29 @@ use OCA\Files_Sharing\ISharedMountPoint; use OCP\Files\Cache\ICacheEntry; use OCP\Files\Mount\IMountPoint; +use OCP\Files\Storage\IStorage; use OCP\IUser; +use Override; /** * @template-implements \ArrayAccess */ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { private array|ICacheEntry $data; - /** - * @var string - */ - private $path; - - /** - * @var \OC\Files\Storage\Storage $storage - */ - private $storage; - - /** - * @var string - */ - private $internalPath; - - /** - * @var \OCP\Files\Mount\IMountPoint - */ - private $mount; - + private string $path; + private IStorage $storage; + private string $internalPath; + private IMountPoint $mount; private ?IUser $owner; - - /** - * @var string[] - */ + /** @var string[] */ private array $childEtags = []; - - /** - * @var IMountPoint[] - */ + /** @var IMountPoint[] */ private array $subMounts = []; - private bool $subMountsUsed = false; - - /** - * The size of the file/folder without any sub mount - */ + /** The size of the file/folder without any sub mount */ private int|float $rawSize = 0; - /** - * @param string|boolean $path - * @param Storage\Storage $storage - * @param string $internalPath - * @param array|ICacheEntry $data - * @param IMountPoint $mount - * @param ?IUser $owner - */ - public function __construct($path, $storage, $internalPath, $data, $mount, $owner = null) { + public function __construct(string|bool $path, IStorage $storage, string $internalPath, array|ICacheEntry $data, IMountPoint $mount, ?IUser $owner = null) { $this->path = $path; $this->storage = $storage; $this->internalPath = $internalPath; @@ -106,30 +74,23 @@ public function offsetGet(mixed $offset): mixed { }; } - /** - * @return string - */ - public function getPath() { + #[Override] + public function getPath(): string { return $this->path; } - public function getStorage() { + #[Override] + public function getStorage(): IStorage { return $this->storage; } - /** - * @return string - */ - public function getInternalPath() { + #[Override] + public function getInternalPath(): string { return $this->internalPath; } - /** - * Get FileInfo ID or null in case of part file - * - * @return int|null - */ - public function getId() { + #[Override] + public function getId(): ?int { return isset($this->data['fileid']) ? (int)$this->data['fileid'] : null; } @@ -137,40 +98,31 @@ public function getMimetype(): string { return $this->data['mimetype'] ?? 'application/octet-stream'; } - /** - * @return string - */ - public function getMimePart() { + #[Override] + public function getMimePart(): string { return $this->data['mimepart']; } - /** - * @return string - */ - public function getName() { + #[Override] + public function getName(): string { return empty($this->data['name']) ? basename($this->getPath()) : $this->data['name']; } - /** - * @return string - */ - public function getEtag() { + #[Override] + public function getEtag(): string { $this->updateEntryFromSubMounts(); if (count($this->childEtags) > 0) { $combinedEtag = $this->data['etag'] . '::' . implode('::', $this->childEtags); return md5($combinedEtag); } else { - return $this->data['etag']; + return $this->data['etag'] ?? ''; } } - /** - * @param bool $includeMounts - * @return int|float - */ - public function getSize($includeMounts = true) { + #[Override] + public function getSize(bool $includeMounts = true): int|float { if ($includeMounts) { $this->updateEntryFromSubMounts(); @@ -184,18 +136,14 @@ public function getSize($includeMounts = true) { } } - /** - * @return int - */ - public function getMTime() { + #[Override] + public function getMTime(): int { $this->updateEntryFromSubMounts(); return (int)$this->data['mtime']; } - /** - * @return bool - */ - public function isEncrypted() { + #[Override] + public function isEncrypted(): bool { return $this->data['encrypted'] ?? false; } @@ -206,108 +154,81 @@ public function getEncryptedVersion(): int { return isset($this->data['encryptedVersion']) ? (int)$this->data['encryptedVersion'] : 1; } - /** - * @return int - */ - public function getPermissions() { - return (int)$this->data['permissions']; + #[Override] + public function getPermissions(): int { + /** @var \OCP\Constants::PERMISSION_* $permission */ + $permission = (int)$this->data['permissions']; + return $permission; } - /** - * @return string \OCP\Files\FileInfo::TYPE_FILE|\OCP\Files\FileInfo::TYPE_FOLDER - */ - public function getType() { + #[Override] + public function getType(): string { if (!isset($this->data['type'])) { $this->data['type'] = ($this->getMimetype() === self::MIMETYPE_FOLDER) ? self::TYPE_FOLDER : self::TYPE_FILE; } return $this->data['type']; } - public function getData() { + public function getData(): array|ICacheEntry { return $this->data; } - /** - * @param int $permissions - * @return bool - */ - protected function checkPermissions($permissions) { + protected function checkPermissions(int $permissions): bool { return ($this->getPermissions() & $permissions) === $permissions; } - /** - * @return bool - */ - public function isReadable() { + #[Override] + public function isReadable(): bool { return $this->checkPermissions(\OCP\Constants::PERMISSION_READ); } - /** - * @return bool - */ - public function isUpdateable() { + #[Override] + public function isUpdateable(): bool { return $this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE); } - /** - * Check whether new files or folders can be created inside this folder - * - * @return bool - */ - public function isCreatable() { + #[Override] + public function isCreatable(): bool { return $this->checkPermissions(\OCP\Constants::PERMISSION_CREATE); } - /** - * @return bool - */ - public function isDeletable() { + #[Override] + public function isDeletable(): bool { return $this->checkPermissions(\OCP\Constants::PERMISSION_DELETE); } - /** - * @return bool - */ - public function isShareable() { + #[Override] + public function isShareable(): bool { return $this->checkPermissions(\OCP\Constants::PERMISSION_SHARE); } - /** - * Check if a file or folder is shared - * - * @return bool - */ - public function isShared() { + #[Override] + public function isShared(): bool { return $this->mount instanceof ISharedMountPoint; } - public function isMounted() { + #[Override] + public function isMounted(): bool { $isHome = $this->mount instanceof HomeMountPoint; return !$isHome && !$this->isShared(); } - /** - * Get the mountpoint the file belongs to - * - * @return \OCP\Files\Mount\IMountPoint - */ - public function getMountPoint() { + #[Override] + public function getMountPoint(): IMountPoint { return $this->mount; } /** - * Get the owner of the file - * - * @return ?IUser + * Get the owner of the file. */ - public function getOwner() { + public function getOwner(): ?IUser { return $this->owner; } /** * @param IMountPoint[] $mounts */ - public function setSubMounts(array $mounts) { + public function setSubMounts(array $mounts): void { $this->subMounts = $mounts; } @@ -321,21 +242,23 @@ private function updateEntryFromSubMounts(): void { if ($subStorage) { $subCache = $subStorage->getCache(''); $rootEntry = $subCache->get(''); - $this->addSubEntry($rootEntry, $mount->getMountPoint()); + if (!empty($rootEntry)) { + $this->addSubEntry($rootEntry, $mount->getMountPoint()); + } } } } /** - * Add a cache entry which is the child of this folder + * Add a cache entry which is the child of this folder. * - * Sets the size, etag and size to for cross-storage childs + * Sets the size, etag and size to for cross-storage children. * * @param array|ICacheEntry $data cache entry for the child * @param string $entryPath full path of the child entry */ - public function addSubEntry($data, $entryPath) { - if (!$data) { + public function addSubEntry(array|ICacheEntry $data, string $entryPath): void { + if (empty($data)) { return; } $hasUnencryptedSize = isset($data['unencrypted_size']) && $data['unencrypted_size'] > 0; @@ -360,33 +283,32 @@ public function addSubEntry($data, $entryPath) { } } - /** - * @inheritdoc - */ - public function getChecksum() { - return $this->data['checksum']; + #[Override] + public function getChecksum(): string { + return $this->data['checksum'] ?? ''; } + #[Override] public function getExtension(): string { return pathinfo($this->getName(), PATHINFO_EXTENSION); } + #[Override] public function getCreationTime(): int { return (int)$this->data['creation_time']; } + #[Override] public function getUploadTime(): int { return (int)$this->data['upload_time']; } + #[Override] public function getParentId(): int { return $this->data['parent'] ?? -1; } - /** - * @inheritDoc - * @return array - */ + #[Override] public function getMetadata(): array { return $this->data['metadata'] ?? []; } diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php index eb374d9326b3d..9a8dec12797c3 100644 --- a/lib/private/Files/Filesystem.php +++ b/lib/private/Files/Filesystem.php @@ -246,7 +246,7 @@ public static function getMountPoints($path) { * get the storage mounted at $mountPoint * * @param string $mountPoint - * @return \OC\Files\Storage\Storage|null + * @return \OCP\Files\Storage\IStorage|null */ public static function getStorage($mountPoint) { $mount = self::getMountManager()->find($mountPoint); @@ -255,7 +255,7 @@ public static function getStorage($mountPoint) { /** * @param string $id - * @return Mount\MountPoint[] + * @return \OCP\Files\Mount\IMountPoint[] */ public static function getMountByStorageId($id) { return self::getMountManager()->findByStorageId($id); @@ -263,7 +263,7 @@ public static function getMountByStorageId($id) { /** * @param int $id - * @return Mount\MountPoint[] + * @return \OCP\Files\Mount\IMountPoint[] */ public static function getMountByNumericId($id) { return self::getMountManager()->findByNumericId($id); diff --git a/lib/private/Files/Mount/DummyMountPoint.php b/lib/private/Files/Mount/DummyMountPoint.php new file mode 100644 index 0000000000000..c640cb97500e3 --- /dev/null +++ b/lib/private/Files/Mount/DummyMountPoint.php @@ -0,0 +1,70 @@ + new \LogicException('Dummy storage') ]); + } + + public function getStorageId(): string { + return ''; + } + + public function getNumericStorageId(): int { + return -1; + } + + public function getInternalPath($path): string { + return $path; + } + + public function wrapStorage($wrapper): void { + } + + public function getOption($name, $default): mixed { + if ($name === 'previews') { + return false; + } + return $default; + } + + public function getOptions(): array { + return ['previews' => false]; + } + + public function getStorageRootId(): int { + return -1; + } + + public function getMountId(): ?int { + return null; + } + + public function getMountType(): string { + return 'dummy'; + } + + public function getMountProvider(): string { + return ''; + } +} diff --git a/lib/private/Files/Node/File.php b/lib/private/Files/Node/File.php index eb6411d7d137c..f7980005f1d05 100644 --- a/lib/private/Files/Node/File.php +++ b/lib/private/Files/Node/File.php @@ -8,27 +8,18 @@ namespace OC\Files\Node; use OCP\Files\GenericFileException; +use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; -use OCP\Lock\LockedException; +use Override; class File extends Node implements \OCP\Files\File { - /** - * Creates a Folder that represents a non-existing path - * - * @param string $path path - * @return NonExistingFile non-existing node - */ - protected function createNonExistingNode($path) { + #[Override] + protected function createNonExistingNode(string $path): NonExistingFile { return new NonExistingFile($this->root, $this->view, $path); } - /** - * @return string - * @throws NotPermittedException - * @throws GenericFileException - * @throws LockedException - */ - public function getContent() { + #[Override] + public function getContent(): string { if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) { $content = $this->view->file_get_contents($this->path); if ($content === false) { @@ -40,13 +31,8 @@ public function getContent() { } } - /** - * @param string|resource $data - * @throws NotPermittedException - * @throws GenericFileException - * @throws LockedException - */ - public function putContent($data) { + #[Override] + public function putContent($data): void { if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) { $this->sendHooks(['preWrite']); if ($this->view->file_put_contents($this->path, $data) === false) { @@ -59,13 +45,8 @@ public function putContent($data) { } } - /** - * @param string $mode - * @return resource|false - * @throws NotPermittedException - * @throws LockedException - */ - public function fopen($mode) { + #[Override] + public function fopen(string $mode) { $preHooks = []; $postHooks = []; $requiredPermissions = \OCP\Constants::PERMISSION_READ; @@ -100,12 +81,8 @@ public function fopen($mode) { } } - /** - * @throws NotPermittedException - * @throws \OCP\Files\InvalidPathException - * @throws \OCP\Files\NotFoundException - */ - public function delete() { + #[Override] + public function delete(): void { if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) { $this->sendHooks(['preDelete']); $fileInfo = $this->getFileInfo(); @@ -118,22 +95,16 @@ public function delete() { } } - /** - * @param string $type - * @param bool $raw - * @return string - */ - public function hash($type, $raw = false) { - return $this->view->hash($type, $this->path, $raw); - } - - /** - * @inheritdoc - */ - public function getChecksum() { - return $this->getFileInfo()->getChecksum(); + #[Override] + public function hash(string $type, bool $raw = false): string { + $hash = $this->view->hash($type, $this->path, $raw); + if ($hash === false) { + throw new NotFoundException('Unable to compute hash of non-exiting file'); + } + return $hash; } + #[Override] public function getExtension(): string { return $this->getFileInfo()->getExtension(); } diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index b747406e4dfa0..ed2088e9c09a3 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -14,6 +14,7 @@ use OC\Files\Search\SearchQuery; use OC\Files\Utils\PathHelper; use OC\User\LazyUser; +use OCP\Constants; use OCP\Files\Cache\ICacheEntry; use OCP\Files\FileInfo; use OCP\Files\Mount\IMountPoint; @@ -25,30 +26,23 @@ use OCP\Files\Search\ISearchOperator; use OCP\Files\Search\ISearchOrder; use OCP\Files\Search\ISearchQuery; +use OCP\IConfig; use OCP\IUserManager; +use OCP\Server; +use Override; class Folder extends Node implements \OCP\Files\Folder { private ?IUserManager $userManager = null; - private bool $wasDeleted = false; - /** - * Creates a Folder that represents a non-existing path - * - * @param string $path path - * @return NonExistingFolder non-existing node - */ - protected function createNonExistingNode($path) { + #[Override] + protected function createNonExistingNode(string $path): NonExistingFolder { return new NonExistingFolder($this->root, $this->view, $path); } - /** - * @param string $path path relative to the folder - * @return string - * @throws \OCP\Files\NotPermittedException - */ - public function getFullPath($path) { + #[Override] + public function getFullPath(string $path): string { $path = $this->normalizePath($path); if (!$this->isValidPath($path)) { throw new NotPermittedException('Invalid path "' . $path . '"'); @@ -56,31 +50,18 @@ public function getFullPath($path) { return $this->path . $path; } - /** - * @param string $path - * @return string|null - */ - public function getRelativePath($path) { + #[Override] + public function getRelativePath(string $path): ?string { return PathHelper::getRelativePath($this->getPath(), $path); } - /** - * check if a node is a (grand-)child of the folder - * - * @param \OC\Files\Node\Node $node - * @return bool - */ - public function isSubNode($node) { + #[Override] + public function isSubNode(INode $node): bool { return str_starts_with($node->getPath(), $this->path . '/'); } - /** - * get the content of this directory - * - * @return Node[] - * @throws \OCP\Files\NotFoundException - */ - public function getDirectoryListing() { + #[Override] + public function getDirectoryListing(): array { $folderContent = $this->view->getDirectoryContent($this->path, '', $this->getFileInfo(false)); return array_map(function (FileInfo $info) { @@ -106,11 +87,11 @@ protected function createNode(string $path, ?FileInfo $info = null, bool $infoHa } } - public function get($path) { + public function get(string $path): INode { return $this->root->get($this->getFullPath($path)); } - public function nodeExists($path) { + public function nodeExists(string $path): bool { try { $this->get($path); return true; @@ -119,13 +100,9 @@ public function nodeExists($path) { } } - /** - * @param string $path - * @return \OC\Files\Node\Folder - * @throws \OCP\Files\NotPermittedException - */ - public function newFolder($path) { - if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) { + #[Override] + public function newFolder(string $path): self { + if ($this->checkPermissions(Constants::PERMISSION_CREATE)) { $fullPath = $this->getFullPath($path); $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath); $this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]); @@ -154,18 +131,13 @@ public function newFolder($path) { } } - /** - * @param string $path - * @param string | resource | null $content - * @return \OC\Files\Node\File - * @throws \OCP\Files\NotPermittedException - */ - public function newFile($path, $content = null) { + #[Override] + public function newFile(string $path, $content = null): File { if ($path === '') { throw new NotPermittedException('Could not create as provided path is empty'); } $this->recreateIfNeeded(); - if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) { + if ($this->checkPermissions(Constants::PERMISSION_CREATE)) { $fullPath = $this->getFullPath($path); $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath); $this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]); @@ -188,20 +160,16 @@ private function queryFromOperator(ISearchOperator $operator, ?string $uid = nul if ($uid === null) { $user = null; } else { - /** @var IUserManager $userManager */ - $userManager = \OCP\Server::get(IUserManager::class); - $user = $userManager->get($uid); + if ($this->userManager === null) { + $this->userManager = Server::get(IUserManager::class); + } + $user = $this->userManager->get($uid); } return new SearchQuery($operator, $limit, $offset, [], $user); } - /** - * search for files with the name matching $query - * - * @param string|ISearchQuery $query - * @return \OC\Files\Node\Node[] - */ - public function search($query) { + #[Override] + public function search(string|ISearchQuery $query): array { if (is_string($query)) { $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query . '%')); } @@ -215,7 +183,7 @@ public function search($query) { } /** @var QuerySearchHelper $searchHelper */ - $searchHelper = \OC::$server->get(QuerySearchHelper::class); + $searchHelper = Server::get(QuerySearchHelper::class); [$caches, $mountByMountPoint] = $searchHelper->getCachesAndMountPointsForSearch($this->root, $this->path, $limitToHome); $resultsPerCache = $searchHelper->searchInCaches($query, $caches); @@ -262,7 +230,7 @@ private function cacheEntryToFileInfo(IMountPoint $mount, string $appendRoot, IC if ($ownerId !== false) { // Cache the user manager (for performance) if ($this->userManager === null) { - $this->userManager = \OCP\Server::get(IUserManager::class); + $this->userManager = Server::get(IUserManager::class); } $owner = new LazyUser($ownerId, $this->userManager); } @@ -277,13 +245,8 @@ private function cacheEntryToFileInfo(IMountPoint $mount, string $appendRoot, IC ); } - /** - * search for files by mimetype - * - * @param string $mimetype - * @return Node[] - */ - public function searchByMime($mimetype) { + #[Override] + public function searchByMime(string $mimetype): array { if (!str_contains($mimetype, '/')) { $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $mimetype . '/%')); } else { @@ -292,37 +255,30 @@ public function searchByMime($mimetype) { return $this->search($query); } - /** - * search for files by tag - * - * @param string|int $tag name or tag id - * @param string $userId owner of the tags - * @return Node[] - */ - public function searchByTag($tag, $userId) { + #[Override] + public function searchByTag(string|int $tag, string $userId): array { $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'tagname', $tag), $userId); return $this->search($query); } + #[Override] public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0): array { $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'systemtag', $tagName), $userId, $limit, $offset); return $this->search($query); } - /** - * @param int $id - * @return \OCP\Files\Node[] - */ - public function getById($id) { - return $this->root->getByIdInPath((int)$id, $this->getPath()); + #[Override] + public function getById(int $id): array { + return $this->root->getByIdInPath($id, $this->getPath()); } - public function getFirstNodeById(int $id): ?\OCP\Files\Node { + #[Override] + public function getFirstNodeById(int $id): ?INode { return $this->root->getFirstNodeByIdInPath($id, $this->getPath()); } public function getAppDataDirectoryName(): string { - $instanceId = \OC::$server->getConfig()->getSystemValueString('instanceid'); + $instanceId = Server::get(IConfig::class)->getSystemValueString('instanceid'); return 'appdata_' . $instanceId; } @@ -334,9 +290,6 @@ public function getAppDataDirectoryName(): string { * So in that case we directly check the mount of the root if it contains * the id. If it does we check if the path is inside the path we are working * in. - * - * @param int $id - * @return array */ protected function getByIdInRootMount(int $id): array { if (!method_exists($this->root, 'createNode')) { @@ -369,12 +322,14 @@ protected function getByIdInRootMount(int $id): array { ))]; } - public function getFreeSpace() { + #[Override] + public function getFreeSpace(): float|int|false { return $this->view->free_space($this->path); } - public function delete() { - if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) { + #[Override] + public function delete(): void { + if ($this->checkPermissions(Constants::PERMISSION_DELETE)) { $this->sendHooks(['preDelete']); $fileInfo = $this->getFileInfo(); $this->view->rmdir($this->path); @@ -386,24 +341,14 @@ public function delete() { } } - /** - * Add a suffix to the name in case the file exists - * - * @param string $name - * @return string - * @throws NotPermittedException - */ - public function getNonExistingName($name) { + #[Override] + public function getNonExistingName(string $name): string { $uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view); return trim($this->getRelativePath($uniqueName), '/'); } - /** - * @param int $limit - * @param int $offset - * @return INode[] - */ - public function getRecent($limit, $offset = 0) { + #[Override] + public function getRecent(int $limit, int $offset = 0): array { $filterOutNonEmptyFolder = new SearchBinaryOperator( // filter out non empty folders ISearchBinaryOperator::OPERATOR_OR, @@ -466,7 +411,8 @@ public function getRecent($limit, $offset = 0) { return $this->search($query); } - public function verifyPath($fileName, $readonly = false): void { + #[Override] + public function verifyPath(string $fileName, bool $readonly = false): void { $this->view->verifyPath( $this->getPath(), $fileName, diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php index ceadc4cad1e9c..43acde6531bb7 100644 --- a/lib/private/Files/Node/LazyFolder.php +++ b/lib/private/Files/Node/LazyFolder.php @@ -14,6 +14,10 @@ use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountPoint; use OCP\Files\NotPermittedException; +use OCP\Files\Search\ISearchQuery; +use OCP\Files\Storage\IStorage; +use OCP\IUser; +use Override; /** * Class LazyFolder @@ -31,7 +35,6 @@ class LazyFolder implements Folder { protected array $data; /** - * @param IRootFolder $rootFolder * @param \Closure(): Folder $folderClosure * @param array $data */ @@ -64,240 +67,133 @@ public function __call($method, $args) { return call_user_func_array([$this->getRealFolder(), $method], $args); } - /** - * @inheritDoc - */ - public function getUser() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function listen($scope, $method, callable $callback) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function removeListener($scope = null, $method = null, ?callable $callback = null) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function emit($scope, $method, $arguments = []) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function mount($storage, $mountPoint, $arguments = []) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMount(string $mountPoint): IMountPoint { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @return IMountPoint[] - */ - public function getMountsIn(string $mountPoint): array { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMountByStorageId($storageId) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMountByNumericStorageId($numericId) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function unMount($mount) { - $this->__call(__FUNCTION__, func_get_args()); - } - - public function get($path) { + #[Override] + public function get(string $path): \OCP\Files\Node { return $this->getRootFolder()->get($this->getFullPath($path)); } - /** - * @inheritDoc - */ - public function rename($targetPath) { + #[Override] + public function move(string $targetPath): \OCP\Files\Node { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function delete() { - return $this->__call(__FUNCTION__, func_get_args()); + #[Override] + public function delete(): void { + $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function copy($targetPath) { + #[Override] + public function copy(string $targetPath): \OCP\Files\Node { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function touch($mtime = null) { + #[Override] + public function touch(?int $mtime = null): void { $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getStorage() { + #[Override] + public function getStorage(): IStorage { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getPath() { + #[Override] + public function getPath(): string { if (isset($this->data['path'])) { return $this->data['path']; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getInternalPath() { + #[Override] + public function getInternalPath(): string { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getId() { + #[Override] + public function getId(): int { if (isset($this->data['fileid'])) { return $this->data['fileid']; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function stat() { + #[Override] + public function stat(): array { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getMTime() { + #[Override] + public function getMTime(): int { if (isset($this->data['mtime'])) { return $this->data['mtime']; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getSize($includeMounts = true): int|float { + #[Override] + public function getSize(bool $includeMounts = true): int|float { if (isset($this->data['size'])) { return $this->data['size']; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getEtag() { + #[Override] + public function getEtag(): string { if (isset($this->data['etag'])) { return $this->data['etag']; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getPermissions() { + #[Override] + public function getPermissions(): int { if (isset($this->data['permissions'])) { return $this->data['permissions']; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function isReadable() { + #[Override] + public function isReadable(): bool { if (isset($this->data['permissions'])) { return ($this->data['permissions'] & Constants::PERMISSION_READ) == Constants::PERMISSION_READ; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function isUpdateable() { + #[Override] + public function isUpdateable(): bool { if (isset($this->data['permissions'])) { return ($this->data['permissions'] & Constants::PERMISSION_UPDATE) == Constants::PERMISSION_UPDATE; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function isDeletable() { + #[Override] + public function isDeletable(): bool { if (isset($this->data['permissions'])) { return ($this->data['permissions'] & Constants::PERMISSION_DELETE) == Constants::PERMISSION_DELETE; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function isShareable() { + #[Override] + public function isShareable(): bool { if (isset($this->data['permissions'])) { return ($this->data['permissions'] & Constants::PERMISSION_SHARE) == Constants::PERMISSION_SHARE; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getParent() { + #[Override] + public function getParent(): IRootFolder|\OCP\Files\Folder { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getName() { + #[Override] + public function getName(): string { if (isset($this->data['path'])) { return basename($this->data['path']); } @@ -307,13 +203,7 @@ public function getName() { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getUserFolder($userId) { - return $this->__call(__FUNCTION__, func_get_args()); - } - + #[Override] public function getMimetype(): string { if (isset($this->data['mimetype'])) { return $this->data['mimetype']; @@ -321,10 +211,8 @@ public function getMimetype(): string { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getMimePart() { + #[Override] + public function getMimePart(): string { if (isset($this->data['mimetype'])) { [$part,] = explode('/', $this->data['mimetype']); return $part; @@ -332,66 +220,51 @@ public function getMimePart() { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function isEncrypted() { + #[Override] + public function isEncrypted(): bool { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getType() { + #[Override] + public function getType(): string { if (isset($this->data['type'])) { return $this->data['type']; } return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function isShared() { + #[Override] + public function isShared(): bool { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function isMounted() { + #[Override] + public function isMounted(): bool { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getMountPoint() { + #[Override] + public function getMountPoint(): IMountPoint { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getOwner() { + #[Override] + public function getOwner(): ?IUser { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getChecksum() { + #[Override] + public function getChecksum(): string { return $this->__call(__FUNCTION__, func_get_args()); } + #[Override] public function getExtension(): string { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getFullPath($path) { + #[Override] + public function getFullPath(string $path): string { if (isset($this->data['path'])) { $path = PathHelper::normalizePath($path); if (!Filesystem::isValidPath($path)) { @@ -402,148 +275,112 @@ public function getFullPath($path) { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function isSubNode($node) { + #[Override] + public function isSubNode(\OCP\Files\Node $node): bool { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getDirectoryListing() { + #[Override] + public function getDirectoryListing(): array { return $this->__call(__FUNCTION__, func_get_args()); } - public function nodeExists($path) { + #[Override] + public function nodeExists(string $path): bool { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function newFolder($path) { + #[Override] + public function newFolder(string $path): \OCP\Files\Folder { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function newFile($path, $content = null) { + #[Override] + public function newFile(string $path, $content = null): \OCP\Files\File { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function search($query) { + #[Override] + public function search(string|ISearchQuery $query): array { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function searchByMime($mimetype) { + #[Override] + public function searchByMime(string $mimetype): array { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function searchByTag($tag, $userId) { + #[Override] + public function searchByTag(int|string $tag, string $userId): array { return $this->__call(__FUNCTION__, func_get_args()); } - public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0) { + #[Override] + public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0): array { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getById($id) { - return $this->getRootFolder()->getByIdInPath((int)$id, $this->getPath()); + #[Override] + public function getById(int $id): array { + return $this->getRootFolder()->getByIdInPath($id, $this->getPath()); } + #[Override] public function getFirstNodeById(int $id): ?\OCP\Files\Node { return $this->getRootFolder()->getFirstNodeByIdInPath($id, $this->getPath()); } - /** - * @inheritDoc - */ - public function getFreeSpace() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isCreatable() { + #[Override] + public function getFreeSpace(): int|float|false { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getNonExistingName($name) { + #[Override] + public function isCreatable(): bool { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function move($targetPath) { + #[Override] + public function getNonExistingName(string $name): string { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function lock($type) { - return $this->__call(__FUNCTION__, func_get_args()); + #[Override] + public function lock(int $type): void { + $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function changeLock($targetType) { - return $this->__call(__FUNCTION__, func_get_args()); + #[Override] + public function changeLock(int $targetType): void { + $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function unlock($type) { - return $this->__call(__FUNCTION__, func_get_args()); + #[Override] + public function unlock(int $type): void { + $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ - public function getRecent($limit, $offset = 0) { + #[Override] + public function getRecent(int $limit, int $offset = 0): array { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ + #[Override] public function getCreationTime(): int { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - */ + #[Override] public function getUploadTime(): int { return $this->__call(__FUNCTION__, func_get_args()); } - public function getRelativePath($path) { + #[Override] + public function getRelativePath(string $path): ?string { return PathHelper::getRelativePath($this->getPath(), $path); } + #[Override] public function getParentId(): int { if (isset($this->data['parent'])) { return $this->data['parent']; @@ -551,15 +388,13 @@ public function getParentId(): int { return $this->__call(__FUNCTION__, func_get_args()); } - /** - * @inheritDoc - * @return array - */ + #[Override] public function getMetadata(): array { return $this->data['metadata'] ?? $this->__call(__FUNCTION__, func_get_args()); } - public function verifyPath($fileName, $readonly = false): void { + #[Override] + public function verifyPath(string $fileName, $readonly = false): void { $this->__call(__FUNCTION__, func_get_args()); } } diff --git a/lib/private/Files/Node/LazyRoot.php b/lib/private/Files/Node/LazyRoot.php index bc3f3a2e80f38..5259f1ceabb6e 100644 --- a/lib/private/Files/Node/LazyRoot.php +++ b/lib/private/Files/Node/LazyRoot.php @@ -12,6 +12,7 @@ use OCP\Files\Mount\IMountPoint; use OCP\Files\Node; use OCP\Files\Node as INode; +use Override; /** * Class LazyRoot @@ -34,23 +35,48 @@ protected function getRootFolder(): IRootFolder { return $folder; } - public function getUserFolder($userId) { + #[Override] + public function listen($scope, $method, callable $callback): void { + $this->__call(__FUNCTION__, func_get_args()); + } + + #[Override] + public function removeListener($scope = null, $method = null, ?callable $callback = null): void { + $this->__call(__FUNCTION__, func_get_args()); + } + + #[Override] + public function getUserFolder(string $userId): \OCP\Files\Folder { return $this->__call(__FUNCTION__, func_get_args()); } - public function getByIdInPath(int $id, string $path) { + #[Override] + public function getByIdInPath(int $id, string $path): array { return $this->__call(__FUNCTION__, func_get_args()); } + #[Override] public function getFirstNodeByIdInPath(int $id, string $path): ?Node { return $this->__call(__FUNCTION__, func_get_args()); } + #[Override] public function getNodeFromCacheEntryAndMount(ICacheEntry $cacheEntry, IMountPoint $mountPoint): INode { return $this->getRootFolder()->getNodeFromCacheEntryAndMount($cacheEntry, $mountPoint); } + #[Override] public function getAppDataDirectoryName(): string { return $this->__call(__FUNCTION__, func_get_args()); } + + #[Override] + public function getMountsIn(string $mountPoint): array { + return $this->__call(__FUNCTION__, func_get_args()); + } + + #[Override] + public function getMount(string $mountPoint): IMountPoint { + return $this->__call(__FUNCTION__, func_get_args()); + } } diff --git a/lib/private/Files/Node/LazyUserFolder.php b/lib/private/Files/Node/LazyUserFolder.php index d7afb199b913f..9a878f8300d8d 100644 --- a/lib/private/Files/Node/LazyUserFolder.php +++ b/lib/private/Files/Node/LazyUserFolder.php @@ -14,6 +14,7 @@ use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountManager; +use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; use OCP\IUser; use Psr\Log\LoggerInterface; @@ -53,6 +54,7 @@ function () use ($user): Folder { ]); throw $e; } + /** @var Folder $node */ return $node; } catch (NotFoundException $e) { if (!$this->getRootFolder()->nodeExists('/' . $user->getUID())) { @@ -65,7 +67,7 @@ function () use ($user): Folder { ); } - public function getMountPoint() { + public function getMountPoint(): IMountPoint { if ($this->folder !== null) { return $this->folder->getMountPoint(); } diff --git a/lib/private/Files/Node/Node.php b/lib/private/Files/Node/Node.php index fd8d84883d964..c4d332d019e7b 100644 --- a/lib/private/Files/Node/Node.php +++ b/lib/private/Files/Node/Node.php @@ -10,75 +10,56 @@ use OC\Files\Filesystem; use OC\Files\Mount\MoveableMount; use OC\Files\Utils\PathHelper; +use OC\Files\View; use OCP\EventDispatcher\GenericEvent; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\FileInfo; use OCP\Files\InvalidPathException; use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountPoint; use OCP\Files\Node as INode; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; -use OCP\Lock\LockedException; +use OCP\Files\Storage\IStorage; +use OCP\IUser; use OCP\PreConditionNotMetException; +use OCP\Server; +use Override; -// FIXME: this class really should be abstract (+1) -class Node implements INode { +abstract class Node implements INode { /** - * @var \OC\Files\View $view + * @param string $path Absolute path to the node (e.g. /admin/files/folder/file) + * @throws PreConditionNotMetException */ - protected $view; - - protected IRootFolder $root; - - /** - * @var string $path Absolute path to the node (e.g. /admin/files/folder/file) - */ - protected $path; - - protected ?FileInfo $fileInfo; - - protected ?INode $parent; - - private bool $infoHasSubMountsIncluded; - - /** - * @param \OC\Files\View $view - * @param \OCP\Files\IRootFolder $root - * @param string $path - * @param FileInfo $fileInfo - */ - public function __construct(IRootFolder $root, $view, $path, $fileInfo = null, ?INode $parent = null, bool $infoHasSubMountsIncluded = true) { + public function __construct( + protected IRootFolder $root, + protected View $view, + protected string $path, + protected ?FileInfo $fileInfo = null, + protected ?\OCP\Files\Folder $parent = null, + protected bool $infoHasSubMountsIncluded = true, + ) { if (Filesystem::normalizePath($view->getRoot()) !== '/') { throw new PreConditionNotMetException('The view passed to the node should not have any fake root set'); } - $this->view = $view; - $this->root = $root; - $this->path = $path; - $this->fileInfo = $fileInfo; - $this->parent = $parent; - $this->infoHasSubMountsIncluded = $infoHasSubMountsIncluded; } /** - * Creates a Node of the same type that represents a non-existing path + * Creates a Node of the same type that represents a non-existing path. * - * @param string $path path - * @return Node non-existing node * @throws \Exception */ - protected function createNonExistingNode($path) { - throw new \Exception('Must be implemented by subclasses'); - } + abstract protected function createNonExistingNode(string $path): INode; /** - * Returns the matching file info + * Returns the matching file info. * - * @return FileInfo * @throws InvalidPathException * @throws NotFoundException */ - public function getFileInfo(bool $includeMountPoint = true) { - if (!$this->fileInfo) { + public function getFileInfo(bool $includeMountPoint = true): FileInfo { + $fileInfo = $this->fileInfo; + if (!$fileInfo) { if (!Filesystem::isValidPath($this->path)) { throw new InvalidPathException(); } @@ -95,16 +76,15 @@ public function getFileInfo(bool $includeMountPoint = true) { } $this->infoHasSubMountsIncluded = true; } - return $this->fileInfo; + return $fileInfo; } /** * @param string[] $hooks */ - protected function sendHooks($hooks, ?array $args = null) { + protected function sendHooks(array $hooks, ?array $args = null): void { $args = !empty($args) ? $args : [$this]; - /** @var IEventDispatcher $dispatcher */ - $dispatcher = \OC::$server->get(IEventDispatcher::class); + $dispatcher = Server::get(IEventDispatcher::class); foreach ($hooks as $hook) { if (method_exists($this->root, 'emit')) { $this->root->emit('\OC\Files', $hook, $args); @@ -121,30 +101,24 @@ protected function sendHooks($hooks, ?array $args = null) { } /** - * @param int $permissions - * @return bool * @throws InvalidPathException * @throws NotFoundException */ - protected function checkPermissions($permissions) { + protected function checkPermissions(int $permissions): bool { return ($this->getPermissions() & $permissions) === $permissions; } - public function delete() { + #[Override] + public function delete(): void { } - /** - * @param int $mtime - * @throws InvalidPathException - * @throws NotFoundException - * @throws NotPermittedException - */ - public function touch($mtime = null) { + #[Override] + public function touch(?int $mtime = null): void { if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) { $this->sendHooks(['preTouch']); $this->view->touch($this->path, $mtime); $this->sendHooks(['postTouch']); - if ($this->fileInfo) { + if ($this->fileInfo instanceof \OC\Files\FileInfo) { if (is_null($mtime)) { $mtime = time(); } @@ -155,7 +129,8 @@ public function touch($mtime = null) { } } - public function getStorage() { + #[Override] + public function getStorage(): IStorage { $storage = $this->getMountPoint()->getStorage(); if (!$storage) { throw new \Exception('No storage for node'); @@ -163,119 +138,77 @@ public function getStorage() { return $storage; } - /** - * @return string - */ - public function getPath() { + #[Override] + public function getPath(): string { return $this->path; } - /** - * @return string - */ - public function getInternalPath() { + #[Override] + public function getInternalPath(): string { return $this->getFileInfo(false)->getInternalPath(); } /** - * @return int * @throws InvalidPathException * @throws NotFoundException */ - public function getId() { - return $this->getFileInfo(false)->getId() ?? -1; + #[Override] + public function getId(): ?int { + return $this->getFileInfo(false)->getId(); } - /** - * @return array - */ - public function stat() { + #[Override] + public function stat(): array|false { return $this->view->stat($this->path); } - /** - * @return int - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getMTime() { + #[Override] + public function getMTime(): int { return $this->getFileInfo()->getMTime(); } - /** - * @param bool $includeMounts - * @return int|float - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getSize($includeMounts = true): int|float { + #[Override] + public function getSize(bool $includeMounts = true): int|float { return $this->getFileInfo()->getSize($includeMounts); } - /** - * @return string - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getEtag() { + #[Override] + public function getEtag(): string { return $this->getFileInfo()->getEtag(); } - /** - * @return int - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getPermissions() { + #[Override] + public function getPermissions(): int { return $this->getFileInfo(false)->getPermissions(); } - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isReadable() { + #[Override] + public function isReadable(): bool { return $this->getFileInfo(false)->isReadable(); } - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isUpdateable() { + #[Override] + public function isUpdateable(): bool { return $this->getFileInfo(false)->isUpdateable(); } - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isDeletable() { + #[Override] + public function isDeletable(): bool { return $this->getFileInfo(false)->isDeletable(); } - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isShareable() { + #[Override] + public function isShareable(): bool { return $this->getFileInfo(false)->isShareable(); } - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isCreatable() { + #[Override] + public function isCreatable(): bool { return $this->getFileInfo(false)->isCreatable(); } - public function getParent(): INode|IRootFolder { + #[Override] + public function getParent(): \OCP\Files\Folder { if ($this->parent === null) { $newPath = dirname($this->path); if ($newPath === '' || $newPath === '.' || $newPath === '/') { @@ -286,8 +219,9 @@ public function getParent(): INode|IRootFolder { try { $fileInfo = $this->getFileInfo(); } catch (NotFoundException) { - $this->parent = $this->root->get($newPath); - /** @var \OCP\Files\Folder $this->parent */ + /** @var \OCP\Files\Folder $parent */ + $parent = $this->root->get($newPath); + $this->parent = $parent; return $this->parent; } @@ -306,102 +240,84 @@ public function getParent(): INode|IRootFolder { return $this->parent; } - /** - * @return string - */ - public function getName() { + #[Override] + public function getName(): string { return basename($this->path); } - /** - * @param string $path - * @return string - */ - protected function normalizePath($path) { + protected function normalizePath(string $path): string { return PathHelper::normalizePath($path); } /** - * check if the requested path is valid - * - * @param string $path - * @return bool + * Check if the requested path is valid. */ - public function isValidPath($path) { + public function isValidPath(string $path): bool { return Filesystem::isValidPath($path); } - public function isMounted() { + #[Override] + public function isMounted(): bool { return $this->getFileInfo(false)->isMounted(); } - public function isShared() { + #[Override] + public function isShared(): bool { return $this->getFileInfo(false)->isShared(); } + #[Override] public function getMimeType(): string { return $this->getFileInfo(false)->getMimetype(); } - public function getMimePart() { + #[Override] + public function getMimePart(): string { return $this->getFileInfo(false)->getMimePart(); } - public function getType() { + #[Override] + public function getType(): string { return $this->getFileInfo(false)->getType(); } - public function isEncrypted() { + #[Override] + public function isEncrypted(): bool { return $this->getFileInfo(false)->isEncrypted(); } - public function getMountPoint() { + #[Override] + public function getMountPoint(): IMountPoint { return $this->getFileInfo(false)->getMountPoint(); } - public function getOwner() { + #[Override] + public function getOwner(): ?IUser { return $this->getFileInfo(false)->getOwner(); } - public function getChecksum() { - } - + #[Override] public function getExtension(): string { return $this->getFileInfo(false)->getExtension(); } - /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @throws LockedException - */ - public function lock($type) { + #[Override] + public function lock(int $type): void { $this->view->lockFile($this->path, $type); } - /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @throws LockedException - */ - public function changeLock($type) { - $this->view->changeLock($this->path, $type); + #[Override] + public function changeLock(int $targetType): void { + $this->view->changeLock($this->path, $targetType); } - /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @throws LockedException - */ - public function unlock($type) { + #[Override] + public function unlock(int $type): void { $this->view->unlockFile($this->path, $type); } - /** - * @param string $targetPath - * @return INode - * @throws InvalidPathException - * @throws NotFoundException - * @throws NotPermittedException if copy not allowed or failed - */ - public function copy($targetPath) { + #[Override] + public function copy(string $targetPath): INode { $targetPath = $this->normalizePath($targetPath); $parent = $this->root->get(dirname($targetPath)); if ($parent instanceof Folder && $this->isValidPath($targetPath) && $parent->isCreatable()) { @@ -420,16 +336,10 @@ public function copy($targetPath) { } } - /** - * @param string $targetPath - * @return INode - * @throws InvalidPathException - * @throws NotFoundException - * @throws NotPermittedException if move not allowed or failed - * @throws LockedException - */ - public function move($targetPath) { + #[Override] + public function move(string $targetPath): INode { $targetPath = $this->normalizePath($targetPath); + $parent = $this->root->get(dirname($targetPath)); if ( ($parent instanceof Folder) @@ -450,12 +360,10 @@ public function move($targetPath) { } $mountPoint = $this->getMountPoint(); - if ($mountPoint) { - // update the cached fileinfo with the new (internal) path - /** @var \OC\Files\FileInfo $oldFileInfo */ - $oldFileInfo = $this->getFileInfo(); - $this->fileInfo = new \OC\Files\FileInfo($targetPath, $oldFileInfo->getStorage(), $mountPoint->getInternalPath($targetPath), $oldFileInfo->getData(), $mountPoint, $oldFileInfo->getOwner()); - } + // update the cached fileinfo with the new (internal) path + /** @var \OC\Files\FileInfo $oldFileInfo */ + $oldFileInfo = $this->getFileInfo(); + $this->fileInfo = new \OC\Files\FileInfo($targetPath, $oldFileInfo->getStorage(), $mountPoint->getInternalPath($targetPath), $oldFileInfo->getData(), $mountPoint, $oldFileInfo->getOwner()); $targetNode = $this->root->get($targetPath); $this->sendHooks(['postRename'], [$this, $targetNode]); @@ -467,23 +375,28 @@ public function move($targetPath) { } } + #[Override] public function getCreationTime(): int { return $this->getFileInfo()->getCreationTime(); } + #[Override] public function getUploadTime(): int { return $this->getFileInfo()->getUploadTime(); } + #[Override] public function getParentId(): int { return $this->fileInfo->getParentId(); } - /** - * @inheritDoc - * @return array - */ + #[Override] public function getMetadata(): array { return $this->fileInfo->getMetadata(); } + + #[Override] + public function getChecksum(): string { + return $this->getFileInfo()->getChecksum(); + } } diff --git a/lib/private/Files/Node/NonExistingFile.php b/lib/private/Files/Node/NonExistingFile.php index 7fb375b941adc..82b11e4049b2e 100644 --- a/lib/private/Files/Node/NonExistingFile.php +++ b/lib/private/Files/Node/NonExistingFile.php @@ -8,29 +8,31 @@ namespace OC\Files\Node; use OCP\Files\NotFoundException; +use Override; class NonExistingFile extends File { - /** - * @param string $newPath - * @throws \OCP\Files\NotFoundException - */ - public function rename($newPath) { + #[Override] + public function move(string $targetPath): \OCP\Files\Node { throw new NotFoundException(); } - public function delete() { + #[Override] + public function delete(): void { throw new NotFoundException(); } - public function copy($targetPath) { + #[Override] + public function copy(string $targetPath): \OCP\Files\Node { throw new NotFoundException(); } - public function touch($mtime = null) { + #[Override] + public function touch(?int $mtime = null): void { throw new NotFoundException(); } - public function getId() { + #[Override] + public function getId(): ?int { if ($this->fileInfo) { return parent::getId(); } else { @@ -38,7 +40,8 @@ public function getId() { } } - public function getInternalPath() { + #[Override] + public function getInternalPath(): string { if ($this->fileInfo) { return parent::getInternalPath(); } else { @@ -46,11 +49,13 @@ public function getInternalPath() { } } - public function stat() { + #[Override] + public function stat(): array { throw new NotFoundException(); } - public function getMTime() { + #[Override] + public function getMTime(): int { if ($this->fileInfo) { return parent::getMTime(); } else { @@ -58,7 +63,8 @@ public function getMTime() { } } - public function getSize($includeMounts = true): int|float { + #[Override] + public function getSize(bool $includeMounts = true): int|float { if ($this->fileInfo) { return parent::getSize($includeMounts); } else { @@ -66,7 +72,8 @@ public function getSize($includeMounts = true): int|float { } } - public function getEtag() { + #[Override] + public function getEtag(): string { if ($this->fileInfo) { return parent::getEtag(); } else { @@ -74,7 +81,8 @@ public function getEtag() { } } - public function getPermissions() { + #[Override] + public function getPermissions(): int { if ($this->fileInfo) { return parent::getPermissions(); } else { @@ -82,7 +90,8 @@ public function getPermissions() { } } - public function isReadable() { + #[Override] + public function isReadable(): bool { if ($this->fileInfo) { return parent::isReadable(); } else { @@ -90,7 +99,8 @@ public function isReadable() { } } - public function isUpdateable() { + #[Override] + public function isUpdateable(): bool { if ($this->fileInfo) { return parent::isUpdateable(); } else { @@ -98,7 +108,8 @@ public function isUpdateable() { } } - public function isDeletable() { + #[Override] + public function isDeletable(): bool { if ($this->fileInfo) { return parent::isDeletable(); } else { @@ -106,7 +117,8 @@ public function isDeletable() { } } - public function isShareable() { + #[Override] + public function isShareable(): bool { if ($this->fileInfo) { return parent::isShareable(); } else { @@ -114,14 +126,17 @@ public function isShareable() { } } - public function getContent() { + #[Override] + public function getContent(): string { throw new NotFoundException(); } - public function putContent($data) { + #[Override] + public function putContent($data): void { throw new NotFoundException(); } + #[Override] public function getMimeType(): string { if ($this->fileInfo) { return parent::getMimeType(); @@ -130,6 +145,7 @@ public function getMimeType(): string { } } + #[Override] public function fopen($mode) { throw new NotFoundException(); } diff --git a/lib/private/Files/Node/NonExistingFolder.php b/lib/private/Files/Node/NonExistingFolder.php index 4489fdaf01067..89ec2aa77e3a6 100644 --- a/lib/private/Files/Node/NonExistingFolder.php +++ b/lib/private/Files/Node/NonExistingFolder.php @@ -8,29 +8,32 @@ namespace OC\Files\Node; use OCP\Files\NotFoundException; +use OCP\Files\Search\ISearchQuery; +use Override; class NonExistingFolder extends Folder { - /** - * @param string $newPath - * @throws \OCP\Files\NotFoundException - */ - public function rename($newPath) { + #[Override] + public function move(string $targetPath): \OCP\Files\Node { throw new NotFoundException(); } - public function delete() { + #[Override] + public function delete(): void { throw new NotFoundException(); } - public function copy($targetPath) { + #[Override] + public function copy(string $targetPath): \OCP\Files\Node { throw new NotFoundException(); } - public function touch($mtime = null) { + #[Override] + public function touch(?int $mtime = null): void { throw new NotFoundException(); } - public function getId() { + #[Override] + public function getId(): ?int { if ($this->fileInfo) { return parent::getId(); } else { @@ -38,7 +41,8 @@ public function getId() { } } - public function getInternalPath() { + #[Override] + public function getInternalPath(): string { if ($this->fileInfo) { return parent::getInternalPath(); } else { @@ -46,11 +50,13 @@ public function getInternalPath() { } } - public function stat() { + #[Override] + public function stat(): array|false { throw new NotFoundException(); } - public function getMTime() { + #[Override] + public function getMTime(): int { if ($this->fileInfo) { return parent::getMTime(); } else { @@ -58,7 +64,8 @@ public function getMTime() { } } - public function getSize($includeMounts = true): int|float { + #[Override] + public function getSize(bool $includeMounts = true): int|float { if ($this->fileInfo) { return parent::getSize($includeMounts); } else { @@ -66,7 +73,8 @@ public function getSize($includeMounts = true): int|float { } } - public function getEtag() { + #[Override] + public function getEtag(): string { if ($this->fileInfo) { return parent::getEtag(); } else { @@ -74,7 +82,8 @@ public function getEtag() { } } - public function getPermissions() { + #[Override] + public function getPermissions(): int { if ($this->fileInfo) { return parent::getPermissions(); } else { @@ -82,7 +91,8 @@ public function getPermissions() { } } - public function isReadable() { + #[Override] + public function isReadable(): bool { if ($this->fileInfo) { return parent::isReadable(); } else { @@ -90,7 +100,7 @@ public function isReadable() { } } - public function isUpdateable() { + public function isUpdateable(): bool { if ($this->fileInfo) { return parent::isUpdateable(); } else { @@ -98,7 +108,8 @@ public function isUpdateable() { } } - public function isDeletable() { + #[Override] + public function isDeletable(): bool { if ($this->fileInfo) { return parent::isDeletable(); } else { @@ -106,7 +117,8 @@ public function isDeletable() { } } - public function isShareable() { + #[Override] + public function isShareable(): bool { if ($this->fileInfo) { return parent::isShareable(); } else { @@ -114,55 +126,68 @@ public function isShareable() { } } - public function get($path) { + #[Override] + public function get(string $path): \OCP\Files\Node { throw new NotFoundException(); } - public function getDirectoryListing() { + #[Override] + public function getDirectoryListing(): array { throw new NotFoundException(); } - public function nodeExists($path) { + #[Override] + public function nodeExists(string $path): bool { return false; } - public function newFolder($path) { + #[Override] + public function newFolder(string $path): Folder { throw new NotFoundException(); } - public function newFile($path, $content = null) { + #[Override] + public function newFile(string $path, $content = null): File { throw new NotFoundException(); } - public function search($query) { + #[Override] + public function search(string|ISearchQuery $query): array { throw new NotFoundException(); } - public function searchByMime($mimetype) { + #[Override] + public function searchByMime(string $mimetype): array { throw new NotFoundException(); } - public function searchByTag($tag, $userId) { + #[Override] + public function searchByTag(int|string $tag, string $userId): array { throw new NotFoundException(); } + #[Override] public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0): array { throw new NotFoundException(); } - public function getById($id) { + #[Override] + public function getById(int $id): array { throw new NotFoundException(); } + #[Override] public function getFirstNodeById(int $id): ?\OCP\Files\Node { throw new NotFoundException(); } - public function getFreeSpace() { + #[Override] + public function getFreeSpace(): float|int|false { throw new NotFoundException(); } - public function isCreatable() { + #[Override] + public function isCreatable(): bool { if ($this->fileInfo) { return parent::isCreatable(); } else { diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php index 9b0a48fa296fd..3c496d9e016c4 100644 --- a/lib/private/Files/Node/Root.php +++ b/lib/private/Files/Node/Root.php @@ -26,12 +26,14 @@ use OCP\Files\Node as INode; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\Files\Storage\IStorage; use OCP\IAppConfig; use OCP\ICache; use OCP\ICacheFactory; use OCP\IUser; use OCP\IUserManager; use OCP\Server; +use Override; use Psr\Log\LoggerInterface; /** @@ -81,87 +83,42 @@ public function __construct( } /** - * Get the user for which the filesystem is setup - * - * @return \OC\User\User + * @internal Only used in unit tests */ - public function getUser() { + public function getUser(): ?IUser { return $this->user; } - /** - * @param string $scope - * @param string $method - * @param callable $callback - */ + #[Override] public function listen($scope, $method, callable $callback) { $this->emitter->listen($scope, $method, $callback); } - /** - * @param string $scope optional - * @param string $method optional - * @param callable $callback optional - */ + #[Override] public function removeListener($scope = null, $method = null, ?callable $callback = null) { $this->emitter->removeListener($scope, $method, $callback); } - /** - * @param string $scope - * @param string $method - * @param Node[] $arguments - */ - public function emit($scope, $method, $arguments = []) { + public function emit(string $scope, string $method, array $arguments = []) { $this->emitter->emit($scope, $method, $arguments); } - /** - * @param \OC\Files\Storage\Storage $storage - * @param string $mountPoint - * @param array $arguments - */ - public function mount($storage, $mountPoint, $arguments = []) { + public function mount(IStorage $storage, string $mountPoint, array $arguments = []) { $mount = new MountPoint($storage, $mountPoint, $arguments); $this->mountManager->addMount($mount); } + #[Override] public function getMount(string $mountPoint): IMountPoint { return $this->mountManager->find($mountPoint); } - /** - * @param string $mountPoint - * @return \OC\Files\Mount\MountPoint[] - */ + #[Override] public function getMountsIn(string $mountPoint): array { return $this->mountManager->findIn($mountPoint); } - /** - * @param string $storageId - * @return \OC\Files\Mount\MountPoint[] - */ - public function getMountByStorageId($storageId) { - return $this->mountManager->findByStorageId($storageId); - } - - /** - * @param int $numericId - * @return MountPoint[] - */ - public function getMountByNumericStorageId($numericId) { - return $this->mountManager->findByNumericId($numericId); - } - - /** - * @param \OC\Files\Mount\MountPoint $mount - */ - public function unMount($mount) { - $this->mountManager->remove($mount); - } - - public function get($path) { + public function get(string $path): \OCP\Files\Node { $path = $this->normalizePath($path); if ($this->isValidPath($path)) { $fullPath = $this->getFullPath($path); @@ -176,154 +133,105 @@ public function get($path) { } } - //most operations can't be done on the root + // most operations can't be done on the root - /** - * @param string $targetPath - * @return Node - * @throws \OCP\Files\NotPermittedException - */ - public function rename($targetPath) { + #[Override] + public function move(string $targetPath): \OCP\Files\Node { throw new NotPermittedException(); } - public function delete() { + #[Override] + public function delete(): void { throw new NotPermittedException(); } - /** - * @param string $targetPath - * @return Node - * @throws \OCP\Files\NotPermittedException - */ - public function copy($targetPath) { + #[Override] + public function copy(string $targetPath): \OCP\Files\Node { throw new NotPermittedException(); } - /** - * @param int $mtime - * @throws \OCP\Files\NotPermittedException - */ - public function touch($mtime = null) { + #[Override] + public function touch(?int $mtime = null): void { throw new NotPermittedException(); } - /** - * @return \OC\Files\Storage\Storage - * @throws \OCP\Files\NotFoundException - */ - public function getStorage() { + #[Override] + public function getStorage(): IStorage { throw new NotFoundException(); } - /** - * @return string - */ - public function getPath() { + #[Override] + public function getPath(): string { return '/'; } - /** - * @return string - */ - public function getInternalPath() { + #[Override] + public function getInternalPath(): string { return ''; } - /** - * @return int - */ - public function getId() { + #[Override] + public function getId(): ?int { return 0; } - /** - * @return array - */ - public function stat() { + #[Override] + public function stat(): array { return []; } - /** - * @return int - */ - public function getMTime() { + #[Override] + public function getMTime(): int { return 0; } - /** - * @param bool $includeMounts - * @return int|float - */ - public function getSize($includeMounts = true): int|float { + #[Override] + public function getSize(bool $includeMounts = true): int|float { return 0; } - /** - * @return string - */ - public function getEtag() { + #[Override] + public function getEtag(): string { return ''; } - /** - * @return int - */ - public function getPermissions() { + #[Override] + public function getPermissions(): int { return \OCP\Constants::PERMISSION_CREATE; } - /** - * @return bool - */ - public function isReadable() { + #[Override] + public function isReadable(): bool { return false; } - /** - * @return bool - */ - public function isUpdateable() { + #[Override] + public function isUpdateable(): bool { return false; } - /** - * @return bool - */ - public function isDeletable() { + #[Override] + public function isDeletable(): bool { return false; } - /** - * @return bool - */ - public function isShareable() { + #[Override] + public function isShareable(): bool { return false; } - /** - * @throws \OCP\Files\NotFoundException - */ - public function getParent(): INode|IRootFolder { + #[Override] + public function getParent(): \OCP\Files\Folder { throw new NotFoundException(); } - /** - * @return string - */ - public function getName() { + #[Override] + public function getName(): string { return ''; } - /** - * Returns a view to user's files folder - * - * @param string $userId user ID - * @return \OCP\Files\Folder - * @throws NoUserException - * @throws NotPermittedException - */ - public function getUserFolder($userId) { + #[Override] + public function getUserFolder(string $userId): \OCP\Files\Folder { $userObject = $this->userManager->get($userId); if (is_null($userObject)) { @@ -366,10 +274,11 @@ public function getUserFolder($userId) { return $this->userFolderCache->get($userId); } - public function getUserMountCache() { + public function getUserMountCache(): IUserMountCache { return $this->userMountCache; } + #[Override] public function getFirstNodeByIdInPath(int $id, string $path): ?INode { // scope the cache by user, so we don't return nodes for different users if ($this->user) { @@ -380,7 +289,7 @@ public function getFirstNodeByIdInPath(int $id, string $path): ?INode { $node = $this->get($cachedPath); // by validating that the cached path still has the requested fileid we can work around the need to invalidate the cached path // if the cached path is invalid or a different file now we fall back to the uncached logic - if ($node && $node->getId() === $id) { + if ($node->getId() === $id) { return $node; } } catch (NotFoundException|NotPermittedException) { @@ -399,10 +308,7 @@ public function getFirstNodeByIdInPath(int $id, string $path): ?INode { return $node; } - /** - * @param int $id - * @return Node[] - */ + #[Override] public function getByIdInPath(int $id, string $path): array { $mountCache = $this->getUserMountCache(); if ($path !== '' && strpos($path, '/', 1) > 0) { @@ -497,6 +403,7 @@ public function getByIdInPath(int $id, string $path): array { return $folders; } + #[Override] public function getNodeFromCacheEntryAndMount(ICacheEntry $cacheEntry, IMountPoint $mountPoint): INode { $path = $cacheEntry->getPath(); $fullPath = $mountPoint->getMountPoint() . $path; diff --git a/lib/private/Files/SimpleFS/NewSimpleFile.php b/lib/private/Files/SimpleFS/NewSimpleFile.php index d0986592c0349..b9f13155b2985 100644 --- a/lib/private/Files/SimpleFS/NewSimpleFile.php +++ b/lib/private/Files/SimpleFS/NewSimpleFile.php @@ -14,6 +14,7 @@ use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\Files\SimpleFS\ISimpleFile; +use Override; class NewSimpleFile implements ISimpleFile { private Folder $parentFolder; @@ -68,21 +69,10 @@ public function getMTime(): int { } } - /** - * Get the content - * - * @throws NotFoundException - * @throws NotPermittedException - */ + #[Override] public function getContent(): string { if ($this->file) { - $result = $this->file->getContent(); - - if ($result === false) { - $this->checkFile(); - } - - return $result; + return $this->file->getContent(); } else { return ''; } diff --git a/lib/private/Files/SimpleFS/SimpleFile.php b/lib/private/Files/SimpleFS/SimpleFile.php index d9c1b47d2f19f..b0aadd9e5ee79 100644 --- a/lib/private/Files/SimpleFS/SimpleFile.php +++ b/lib/private/Files/SimpleFS/SimpleFile.php @@ -12,6 +12,7 @@ use OCP\Files\NotPermittedException; use OCP\Files\SimpleFS\ISimpleFile; use OCP\Lock\LockedException; +use Override; class SimpleFile implements ISimpleFile { private File $file; @@ -48,22 +49,9 @@ public function getMTime(): int { return $this->file->getMTime(); } - /** - * Get the content - * - * @throws GenericFileException - * @throws LockedException - * @throws NotFoundException - * @throws NotPermittedException - */ + #[Override] public function getContent(): string { - $result = $this->file->getContent(); - - if ($result === false) { - $this->checkFile(); - } - - return $result; + return $this->file->getContent(); } /** @@ -158,6 +146,6 @@ public function write() { } public function getId(): int { - return $this->file->getId(); + return $this->file->getId() ?? -1; } } diff --git a/lib/private/Files/Utils/PathHelper.php b/lib/private/Files/Utils/PathHelper.php index c1a8d0d1a6653..724ce425a0ec1 100644 --- a/lib/private/Files/Utils/PathHelper.php +++ b/lib/private/Files/Utils/PathHelper.php @@ -29,10 +29,6 @@ public static function getRelativePath(string $root, string $path) { } } - /** - * @param string $path - * @return string - */ public static function normalizePath(string $path): string { if ($path === '' || $path === '/') { return '/'; diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index ecf2f438edb1f..2ef700084a107 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -343,7 +343,7 @@ public function is_file($path) { * @param string $path * @return mixed */ - public function stat($path) { + public function stat($path): array|false { return $this->basicOperation('stat', $path); } @@ -1124,12 +1124,7 @@ public function getMimeType($path) { return $this->basicOperation('getMimeType', $path); } - /** - * @param string $type - * @param string $path - * @param bool $raw - */ - public function hash($type, $path, $raw = false): string|bool { + public function hash(string $type, string $path, bool $raw = false): string|false { $postFix = (substr($path, -1) === '/') ? '/' : ''; $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); if (Filesystem::isValidPath($path)) { @@ -1154,11 +1149,9 @@ public function hash($type, $path, $raw = false): string|bool { } /** - * @param string $path - * @return mixed * @throws InvalidPathException */ - public function free_space($path = '/') { + public function free_space(string $path = '/'): float|int|false { $this->assertPathLength($path); $result = $this->basicOperation('free_space', $path); if ($result === null) { diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php index 82c4ec88363f2..a5996fae2cb23 100644 --- a/lib/private/Preview/Generator.php +++ b/lib/private/Preview/Generator.php @@ -98,7 +98,8 @@ public function getPreview( */ public function generatePreviews(File $file, array $specifications, ?string $mimeType = null, bool $cacheResult = true): ISimpleFile { //Make sure that we can read the file - if (!$file->isReadable()) { + $id = $file->getId(); + if ($id === null || !$file->isReadable()) { $this->logger->warning('Cannot read file: {path}, skipping preview generation.', ['path' => $file->getPath()]); throw new NotFoundException('Cannot read file'); } @@ -107,7 +108,7 @@ public function generatePreviews(File $file, array $specifications, ?string $mim $mimeType = $file->getMimeType(); } - [$file->getId() => $previews] = $this->previewMapper->getAvailablePreviews([$file->getId()]); + [$id => $previews] = $this->previewMapper->getAvailablePreviews([$id]); $previewVersion = null; if ($file instanceof IVersionedPreviewFile) { diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php index fb88409287260..3efb4bfb22dc0 100644 --- a/lib/private/PreviewManager.php +++ b/lib/private/PreviewManager.php @@ -225,7 +225,7 @@ public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null) } $mount = $file->getMountPoint(); - if ($mount && !$mount->getOption('previews', true)) { + if (!$mount->getOption('previews', true)) { return false; } diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 5300e6e1baad2..45f989e12b0bc 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -646,9 +646,7 @@ private function getSharesInFolderInternal(?string $userId, Folder $node, ?bool $childMountNodes = array_filter($node->getDirectoryListing(), function (Node $node): bool { return $node->getInternalPath() === ''; }); - $childMountRootIds = array_map(function (Node $node): int { - return $node->getId(); - }, $childMountNodes); + $childMountRootIds = array_map(fn (Node $node): int => $node->getId() ?? -1, $childMountNodes); $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid')); $qb->andWhere( diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index d69add2d80bea..c831e4b456502 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -123,7 +123,7 @@ public function transcribeFile(File $file, ?string $userId = null, string $appId if (isset($this->taskProcessingManager->getAvailableTaskTypes()['core:audio2text'])) { $taskProcessingTask = new Task( AudioToText::ID, - ['input' => $file->getId()], + ['input' => $file->getId() ?? -1], $appId, $userId, 'from-SpeechToTextManager||' . $file->getId() . '||' . ($userId ?? '') . '||' . $appId, diff --git a/lib/public/Files/File.php b/lib/public/Files/File.php index 67b7a7d0d2ad7..be98e76d88110 100644 --- a/lib/public/Files/File.php +++ b/lib/public/Files/File.php @@ -1,12 +1,12 @@ + * @throws InvalidPathException + * @throws NotFoundException * @since 7.0.0 - namespace of constants has changed in 8.0.0 */ - public function getPermissions(); + public function getPermissions(): int; /** * Check whether this is a file or a folder * - * @return string \OCP\Files\FileInfo::TYPE_FILE|\OCP\Files\FileInfo::TYPE_FOLDER + * @return FileInfo::TYPE_FILE|FileInfo::TYPE_FOLDER * @since 7.0.0 */ - public function getType(); + public function getType(): string; /** - * Check if the file or folder is readable + * Check if the file or folder is readable. * - * @return bool + * @throws NotFoundException + * @throws InvalidPathException * @since 7.0.0 */ - public function isReadable(); + public function isReadable(): bool; /** - * Check if a file is writable + * Check if the file or folder is writable. * - * @return bool + * @throws InvalidPathException + * @throws NotFoundException * @since 7.0.0 */ - public function isUpdateable(); + public function isUpdateable(): bool; /** * Check whether new files or folders can be created inside this folder * - * @return bool + * @throws InvalidPathException + * @throws NotFoundException * @since 8.0.0 */ - public function isCreatable(); + public function isCreatable(): bool; /** * Check if a file or folder can be deleted * - * @return bool + * @throws InvalidPathException + * @throws NotFoundException * @since 7.0.0 */ - public function isDeletable(); + public function isDeletable(): bool; /** - * Check if a file or folder can be shared + * Check if the file or folder is shareable. * - * @return bool + * @throws InvalidPathException + * @throws NotFoundException * @since 7.0.0 */ - public function isShareable(); + public function isShareable(): bool; /** - * Check if a file or folder is shared + * Check if a file or folder is shared. * - * @return bool * @since 7.0.0 */ - public function isShared(); + public function isShared(): bool; /** * Check if a file or folder is mounted * - * @return bool * @since 7.0.0 */ - public function isMounted(); + public function isMounted(): bool; /** - * Get the mountpoint the file belongs to + * Get the mountpoint the file belongs to. * - * @return \OCP\Files\Mount\IMountPoint * @since 8.0.0 */ - public function getMountPoint(); + public function getMountPoint(): IMountPoint; /** - * Get the owner of the file + * Get the owner of the file. * - * @return ?\OCP\IUser * @since 9.0.0 */ - public function getOwner(); + public function getOwner(): ?IUser; /** - * Get the stored checksum(s) for this file + * Get the stored checksum(s) for this file. * * Checksums are stored in the format TYPE:CHECKSUM, here may be multiple checksums separated by a single space * e.g. MD5:d3b07384d113edec49eaa6238ad5ff00 SHA1:f1d2d2f924e986ac86fdf7b36c94bcdf32beec15 * - * @return string + * @note This will return an empty string if no checksum is currently stored. + * * @since 9.0.0 */ - public function getChecksum(); + public function getChecksum(): string; /** * Get the extension of the file @@ -275,7 +288,7 @@ public function getCreationTime(): int; * If the upload time is not known, 0 will be returned * * Upload time will be set automatically by the server for files uploaded over DAV - * files created by Nextcloud apps generally do not have an the upload time set + * files created by Nextcloud apps generally do not have the upload time set. * * @return int * @since 18.0.0 @@ -283,16 +296,15 @@ public function getCreationTime(): int; public function getUploadTime(): int; /** - * Get the fileid or the parent folder - * or -1 if this item has no parent folder (because it is the root) + * Get the fileId or the parent folder or -1 if this item has no parent folder + * (because it is the root). * - * @return int * @since 28.0.0 */ public function getParentId(): int; /** - * Get the metadata, if available + * Get the metadata, if available. * * @return array * @since 28.0.0 diff --git a/lib/public/Files/Folder.php b/lib/public/Files/Folder.php index a35d2d78bc90e..055df445bb49e 100644 --- a/lib/public/Files/Folder.php +++ b/lib/public/Files/Folder.php @@ -10,146 +10,143 @@ namespace OCP\Files; +use OCP\AppFramework\Attribute\Consumable; use OCP\Files\Search\ISearchQuery; /** + * Folder interface. + * + * Represents a container node that can hold files, subfolders, + * or other nodes in a hierarchical structure. + * * @since 6.0.0 */ +#[Consumable(since: '6.0.0')] interface Folder extends Node { /** * Get the full path of an item in the folder within owncloud's filesystem * * @param string $path relative path of an item in the folder * @return string - * @throws \OCP\Files\NotPermittedException + * @throws NotPermittedException * @since 6.0.0 */ - public function getFullPath($path); + public function getFullPath(string $path): string; /** * Get the path of an item in the folder relative to the folder * * @param string $path absolute path of an item in the folder - * @throws \OCP\Files\NotFoundException - * @return string|null + * @throws NotFoundException * @since 6.0.0 */ - public function getRelativePath($path); + public function getRelativePath(string $path): ?string; /** - * check if a node is a (grand-)child of the folder + * Check if a node is a (grand-)child of the folder. * - * @param \OCP\Files\Node $node - * @return bool * @since 6.0.0 */ - public function isSubNode($node); + public function isSubNode(Node $node): bool; /** - * get the content of this directory + * Get the content of this directory. * - * @throws \OCP\Files\NotFoundException - * @return \OCP\Files\Node[] + * @return Node[] + * @throws NotFoundException * @since 6.0.0 */ - public function getDirectoryListing(); + public function getDirectoryListing(): array; /** - * Get the node at $path + * Get the node at $path. * * @param string $path relative path of the file or folder - * @return \OCP\Files\Node - * @throws \OCP\Files\NotFoundException - * @throws \OCP\Files\NotPermittedException + * @throws NotFoundException + * @throws NotPermittedException * @since 6.0.0 */ - public function get($path); + public function get(string $path): Node; /** * Check if a file or folder exists in the folder * * @param string $path relative path of the file or folder - * @return bool * @since 6.0.0 */ - public function nodeExists($path); + public function nodeExists(string $path): bool; /** * Create a new folder * * @param string $path relative path of the new folder - * @return \OCP\Files\Folder - * @throws \OCP\Files\NotPermittedException + * @throws NotPermittedException * @since 6.0.0 */ - public function newFolder($path); + public function newFolder(string $path): Folder; /** * Create a new file * * @param string $path relative path of the new file * @param string|resource|null $content content for the new file, since 19.0.0 - * @return \OCP\Files\File - * @throws \OCP\Files\NotPermittedException + * @throws NotPermittedException * @since 6.0.0 */ - public function newFile($path, $content = null); + public function newFile(string $path, $content = null): File; /** - * search for files with the name matching $query + * Search for files with the name matching $query. * - * @param string|ISearchQuery $query - * @return \OCP\Files\Node[] + * @return Node[] * @since 6.0.0 */ - public function search($query); + public function search(string|ISearchQuery $query): array; /** - * search for files by mimetype - * $mimetype can either be a full mimetype (image/png) or a wildcard mimetype (image) + * Search for files by mimetype. * - * @param string $mimetype - * @return \OCP\Files\Node[] + * @param string $mimetype can either be a full mimetype (image/png) or a wildcard mimetype (image) + * @return Node[] * @since 6.0.0 */ - public function searchByMime($mimetype); + public function searchByMime(string $mimetype): array; /** - * search for files by tag + * Search for files by tag. * * @param string|int $tag tag name or tag id * @param string $userId owner of the tags - * @return \OCP\Files\Node[] + * @return Node[] * @since 8.0.0 */ - public function searchByTag($tag, $userId); + public function searchByTag(string|int $tag, string $userId): array; /** - * search for files by system tag + * Search for files by system tag. * - * @param string|int $tag tag name + * @param string $tag tag name * @param string $userId user id to ensure access on returned nodes - * @return \OCP\Files\Node[] + * @return Node[] * @since 28.0.0 */ - public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0); + public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0): array; /** - * get a file or folder inside the folder by its internal id + * Get a file or folder inside the folder by its internal id. * * This method could return multiple entries. For example once the file/folder * is shared or mounted (files_external) to the user multiple times. * * Note that the different entries can have different permissions. * - * @param int $id - * @return \OCP\Files\Node[] + * @return Node[] * @since 6.0.0 */ - public function getById($id); + public function getById(int $id): array; /** - * get a file or folder inside the folder by its internal id + * Get a file or folder inside the folder by its internal id. * * Unlike getById, this method only returns a single node even if the user has * access to the file with the requested id multiple times. @@ -160,54 +157,47 @@ public function getById($id); * Apps that require accurate information about the users access to the file should use getById * instead of pick the correct node out of the result. * - * @param int $id - * @return Node|null * @since 29.0.0 */ public function getFirstNodeById(int $id): ?Node; /** - * Get the amount of free space inside the folder + * Get the amount of free space inside the folder. * - * @return int * @since 6.0.0 */ - public function getFreeSpace(); + public function getFreeSpace(): int|float|false; /** - * Check if new files or folders can be created within the folder + * Check if new files or folders can be created within the folder. * - * @return bool * @since 6.0.0 */ - public function isCreatable(); + public function isCreatable(): bool; /** - * Add a suffix to the name in case the file exists + * Add a suffix to the name in case the file exists. * - * @param string $name - * @return string * @throws NotPermittedException * @since 8.1.0 */ - public function getNonExistingName($name); + public function getNonExistingName(string $name): string; /** - * @param int $limit - * @param int $offset - * @return \OCP\Files\Node[] + * Get recent files and folders. + * + * @return Node[] * @since 9.1.0 */ - public function getRecent($limit, $offset = 0); + public function getRecent(int $limit, int $offset = 0): array; /** - * Verify if the given path is valid and allowed from this folder. + * Verify if the given fileName is valid and allowed from this folder. * - * @param string $path the path from this folder * @param string $fileName * @param bool $readonly Check only if the path is allowed for read-only access * @throws InvalidPathException * @since 32.0.0 */ - public function verifyPath($fileName, $readonly = false): void; + public function verifyPath(string $fileName, bool $readonly = false): void; } diff --git a/lib/public/Files/IRootFolder.php b/lib/public/Files/IRootFolder.php index fb8532f8c8153..de5b768756999 100644 --- a/lib/public/Files/IRootFolder.php +++ b/lib/public/Files/IRootFolder.php @@ -1,5 +1,7 @@ $this->templateId, 'basename' => $this->file->getName(), 'etag' => $this->file->getEtag(), - 'fileid' => $this->file->getId(), + 'fileid' => $this->file->getId() ?? -1, 'filename' => $this->templateId, 'lastmod' => $this->file->getMTime(), 'mime' => $this->file->getMimetype(), diff --git a/tests/lib/Encryption/DecryptAllTest.php b/tests/lib/Encryption/DecryptAllTest.php index 5b56ac271c576..a5c64f453981b 100644 --- a/tests/lib/Encryption/DecryptAllTest.php +++ b/tests/lib/Encryption/DecryptAllTest.php @@ -15,6 +15,7 @@ use OC\Encryption\Manager; use OC\Files\FileInfo; use OC\Files\View; +use OCP\Files\Mount\IMountPoint; use OCP\Files\Storage\IStorage; use OCP\IUserManager; use OCP\UserInterface; @@ -250,15 +251,15 @@ public function testDecryptUsersFiles(): void { [ '/user1/files', '', null, [ - new FileInfo('path', $storage, 'intPath', ['name' => 'foo', 'type' => 'dir'], null), - new FileInfo('path', $storage, 'intPath', ['name' => 'bar', 'type' => 'file', 'encrypted' => true], null), - new FileInfo('path', $sharedStorage, 'intPath', ['name' => 'shared', 'type' => 'file', 'encrypted' => true], null), + new FileInfo('path', $storage, 'intPath', ['name' => 'foo', 'type' => 'dir'], $this->createMock(IMountPoint::class)), + new FileInfo('path', $storage, 'intPath', ['name' => 'bar', 'type' => 'file', 'encrypted' => true], $this->createMock(IMountPoint::class)), + new FileInfo('path', $sharedStorage, 'intPath', ['name' => 'shared', 'type' => 'file', 'encrypted' => true], $this->createMock(IMountPoint::class)), ], ], [ '/user1/files/foo', '', null, [ - new FileInfo('path', $storage, 'intPath', ['name' => 'subfile', 'type' => 'file', 'encrypted' => true], null) + new FileInfo('path', $storage, 'intPath', ['name' => 'subfile', 'type' => 'file', 'encrypted' => true], $this->createMock(IMountPoint::class)) ], ], ]); diff --git a/tests/lib/Files/Node/FileTest.php b/tests/lib/Files/Node/FileTest.php index 0ab8a32b6cbd0..8af78a447c7b4 100644 --- a/tests/lib/Files/Node/FileTest.php +++ b/tests/lib/Files/Node/FileTest.php @@ -10,8 +10,12 @@ use OC\Files\Node\File; use OC\Files\Node\Root; +use OC\Files\View; use OCP\Constants; +use OCP\Files\IRootFolder; +use OCP\Files\Node; use OCP\Files\NotPermittedException; +use PHPUnit\Framework\MockObject\MockObject; /** * Class FileTest @@ -21,7 +25,7 @@ * @package Test\Files\Node */ class FileTest extends NodeTestCase { - protected function createTestNode($root, $view, $path, array $data = [], $internalPath = '', $storage = null) { + protected function createTestNode(IRootFolder $root, View&MockObject $view, string $path, array $data = [], $internalPath = '', $storage = null): Node { if ($data || $internalPath || $storage) { return new File($root, $view, $path, $this->getFileInfo($data, $internalPath, $storage)); } else { diff --git a/tests/lib/Files/Node/FolderTest.php b/tests/lib/Files/Node/FolderTest.php index fc8b778cb3474..17f3248eb1030 100644 --- a/tests/lib/Files/Node/FolderTest.php +++ b/tests/lib/Files/Node/FolderTest.php @@ -47,7 +47,7 @@ * @package Test\Files\Node */ class FolderTest extends NodeTestCase { - protected function createTestNode($root, $view, $path, array $data = [], $internalPath = '', $storage = null) { + protected function createTestNode(IRootFolder $root, View&MockObject $view, string $path, array $data = [], $internalPath = '', $storage = null): \OCP\Files\Node { $view->expects($this->any()) ->method('getRoot') ->willReturn(''); @@ -86,8 +86,8 @@ public function testGetDirectoryContent(): void { ->method('getDirectoryContent') ->with('/bar/foo') ->willReturn([ - new FileInfo('/bar/foo/asd', null, 'foo/asd', ['fileid' => 2, 'path' => '/bar/foo/asd', 'name' => 'asd', 'size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain'], null), - new FileInfo('/bar/foo/qwerty', null, 'foo/qwerty', ['fileid' => 3, 'path' => '/bar/foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'httpd/unix-directory'], null), + new FileInfo('/bar/foo/asd', $this->createMock(IStorage::class), 'foo/asd', ['fileid' => 2, 'path' => '/bar/foo/asd', 'name' => 'asd', 'size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain'], $this->createMock(IMountPoint::class)), + new FileInfo('/bar/foo/qwerty', $this->createMock(IStorage::class), 'foo/qwerty', ['fileid' => 3, 'path' => '/bar/foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'httpd/unix-directory'], $this->createMock(IMountPoint::class)), ]); $this->view->method('getFileInfo') ->willReturn($this->createMock(FileInfo::class)); @@ -492,12 +492,12 @@ public function testSearchSubStorages(): void { public function testIsSubNode(): void { $rootFolderMock = $this->createMock(IRootFolder::class); - $file = new Node($rootFolderMock, $this->view, '/foo/bar'); + $file = new File($rootFolderMock, $this->view, '/foo/bar'); $folder = new Folder($rootFolderMock, $this->view, '/foo'); $this->assertTrue($folder->isSubNode($file)); $this->assertFalse($folder->isSubNode($folder)); - $file = new Node($rootFolderMock, $this->view, '/foobar'); + $file = new File($rootFolderMock, $this->view, '/foobar'); $this->assertFalse($folder->isSubNode($file)); } diff --git a/tests/lib/Files/Node/NodeTestCase.php b/tests/lib/Files/Node/NodeTestCase.php index 90f7c2c0f65b3..4cf92f329b36d 100644 --- a/tests/lib/Files/Node/NodeTestCase.php +++ b/tests/lib/Files/Node/NodeTestCase.php @@ -92,13 +92,7 @@ protected function getRootViewMock() { return $view; } - /** - * @param IRootFolder $root - * @param View $view - * @param string $path - * @return Node - */ - abstract protected function createTestNode($root, $view, $path, array $data = [], $internalPath = '', $storage = null); + abstract protected function createTestNode(IRootFolder $root, View&MockObject $view, string $path, array $data = [], $internalPath = '', $storage = null): Node; /** * @return string @@ -115,7 +109,7 @@ abstract protected function getNonExistingNodeClass(); */ abstract protected function getViewDeleteMethod(); - protected function getMockStorage() { + protected function getMockStorage(): IStorage&MockObject { $storage = $this->getMockBuilder(IStorage::class) ->disableOriginalConstructor() ->getMock(); @@ -125,10 +119,12 @@ protected function getMockStorage() { return $storage; } - protected function getFileInfo($data, $internalPath = '', $storage = null) { + protected function getFileInfo(array $data, string $internalPath = '', ?IStorage $storage = null): FileInfo { $mount = $this->createMock(IMountPoint::class); $mount->method('getStorage') ->willReturn($storage); + $mount->method('getInternalPath') + ->willReturnArgument(0); return new FileInfo('', $this->getMockStorage(), $internalPath, $data, $mount); } diff --git a/tests/lib/Files/Node/RootTest.php b/tests/lib/Files/Node/RootTest.php index 3821b6943b15b..1b9e0bfe2a161 100644 --- a/tests/lib/Files/Node/RootTest.php +++ b/tests/lib/Files/Node/RootTest.php @@ -19,8 +19,10 @@ use OCP\Cache\CappedMemoryCache; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; +use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\Files\Storage\IStorage; use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IUser; @@ -75,8 +77,8 @@ protected function getRootViewMock() { return $view; } - protected function getFileInfo($data) { - return new FileInfo('', null, '', $data, null); + protected function getFileInfo($data): FileInfo { + return new FileInfo('', $this->createMock(IStorage::class), '', $data, $this->createMock(IMountPoint::class)); } public function testGet(): void { diff --git a/tests/lib/Files/SimpleFS/SimpleFileTest.php b/tests/lib/Files/SimpleFS/SimpleFileTest.php index 6ce5ddad351a0..9b064a5a3142d 100644 --- a/tests/lib/Files/SimpleFS/SimpleFileTest.php +++ b/tests/lib/Files/SimpleFS/SimpleFileTest.php @@ -91,7 +91,7 @@ public function testGetMimeType(): void { public function testGetContentInvalidAppData(): void { $this->file->method('getContent') - ->willReturn(false); + ->willThrowException($this->createMock(NotFoundException::class)); $this->file->method('stat')->willReturn(false); $parent = $this->createMock(Folder::class); diff --git a/tests/lib/Files/ViewTest.php b/tests/lib/Files/ViewTest.php index e7ad9fcc3046f..6f6c845b1922c 100644 --- a/tests/lib/Files/ViewTest.php +++ b/tests/lib/Files/ViewTest.php @@ -959,7 +959,7 @@ public function testPartFileInfo(): void { $info = $view->getFileInfo('test.part'); $this->assertInstanceOf('\OCP\Files\FileInfo', $info); - $this->assertNull($info->getId()); + $this->assertEquals(null, $info->getId()); $this->assertEquals(6, $sizeWritten); $this->assertEquals(6, $info->getSize()); $this->assertEquals('foobar', $view->file_get_contents('test.part')); diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php index aa42b685ffab1..945698c2c74f3 100644 --- a/tests/lib/Share20/ManagerTest.php +++ b/tests/lib/Share20/ManagerTest.php @@ -812,7 +812,7 @@ public function testVerifyPasswordHookFails(): void { } public function createShare($id, $type, $node, $sharedWith, $sharedBy, $shareOwner, - $permissions, $expireDate = null, $password = null, $attributes = null) { + $permissions, $expireDate = null, $password = null, $attributes = null): IShare&MockObject { $share = $this->createMock(IShare::class); $share->method('getShareType')->willReturn($type); @@ -840,6 +840,7 @@ public static function dataGeneralChecks(): array { File::class, [ 'getId' => 108, + 'getPath' => 'path', ], 'default', ]; @@ -848,6 +849,7 @@ public static function dataGeneralChecks(): array { Node::class, [ 'getId' => 108, + 'getPath' => 'path', ], 'default', ]; @@ -887,6 +889,7 @@ public static function dataGeneralChecks(): array { 'getPath' => 'path', 'getName' => 'name', 'getOwner' => $user0, + 'getInternalPath' => 'not-null', ], 'default', ]; @@ -904,6 +907,7 @@ public static function dataGeneralChecks(): array { 'getPath' => 'path', 'getName' => 'name', 'getOwner' => $user0, + 'getInternalPath' => 'not-null', ], 'default', ]; @@ -941,6 +945,8 @@ public static function dataGeneralChecks(): array { 'isShareable' => true, 'getPermissions' => Constants::PERMISSION_ALL, 'getId' => 42, + 'getPath' => 'path', + 'getInternalPath' => 'not-null', ], 'none', ]; @@ -956,6 +962,8 @@ public static function dataGeneralChecks(): array { 'getPermissions' => Constants::PERMISSION_ALL, 'getId' => 187, 'getOwner' => $user0, + 'getPath' => 'path', + 'getInternalPath' => 'not-null', ], 'default', ]; @@ -972,6 +980,8 @@ public static function dataGeneralChecks(): array { 'getPermissions' => Constants::PERMISSION_ALL, 'getId' => 108, 'getOwner' => $user0, + 'getPath' => 'path', + 'getInternalPath' => 'not-null', ], 'default', ]; @@ -996,13 +1006,15 @@ public static function dataGeneralChecks(): array { 'getPermissions' => Constants::PERMISSION_READ ^ Constants::PERMISSION_UPDATE, 'getId' => 108, 'getOwner' => $user0, + 'getPath' => 'path', + 'getInternalPath' => 'not-null', ], 'remote', ]; $data[] = [[null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 1, null, null], null, false]; $data[] = [[null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 3, null, null], null, false]; - $data[] = [[null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 31, null, null], 'Cannot increase permissions of ', true]; + $data[] = [[null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 31, null, null], 'Cannot increase permissions of path', true]; return $data; } @@ -1016,7 +1028,7 @@ private function createNodeMock(string $class, array $methods, string $storageTy $return->method('getUID') ->willReturn($uid); } elseif ($methodName === 'getMountPoint') { - $return = $this->createMock($return); + $return = $this->createMockForIntersectionOfInterfaces([IMountPoint::class, $return]); } $mock->method($methodName)->willReturn($return); } @@ -2986,7 +2998,7 @@ public function testGetSharesBy(): void { } public function testGetSharesByOwnerless(): void { - $mount = $this->createMock(IShareOwnerlessMount::class); + $mount = $this->createMockForIntersectionOfInterfaces([IMountPoint::class, IShareOwnerlessMount::class]); $node = $this->createMock(Folder::class); $node @@ -4622,7 +4634,7 @@ public function testGetSharesInFolderOwnerless(): void { $share1 = $this->createMock(IShare::class); $share2 = $this->createMock(IShare::class); - $mount = $this->createMock(IShareOwnerlessMount::class); + $mount = $this->createMockForIntersectionOfInterfaces([IMountPoint::class, IShareOwnerlessMount::class]); $folder = $this->createMock(Folder::class); $folder diff --git a/tests/lib/Share20/ShareHelperTest.php b/tests/lib/Share20/ShareHelperTest.php index 3928843cf7def..465ab1b6bcd0f 100644 --- a/tests/lib/Share20/ShareHelperTest.php +++ b/tests/lib/Share20/ShareHelperTest.php @@ -8,6 +8,7 @@ namespace Test\Share20; use OC\Share20\ShareHelper; +use OCP\Files\Folder; use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Share\IManager; @@ -109,8 +110,7 @@ public static function dataGetPathsForUsers(): array { public function testGetPathsForUsers(array $users, array $nodes, array $expected): void { $lastNode = null; foreach ($nodes as $nodeId => $nodeName) { - /** @var Node|\PHPUnit\Framework\MockObject\MockObject $node */ - $node = $this->createMock(Node::class); + $node = $this->createMock(Folder::class); $node->expects($this->any()) ->method('getId') ->willReturn($nodeId); @@ -166,8 +166,7 @@ public static function dataGetPathsForRemotes(): array { public function testGetPathsForRemotes(array $remotes, array $nodes, array $expected): void { $lastNode = null; foreach ($nodes as $nodeId => $nodePath) { - /** @var Node|\PHPUnit\Framework\MockObject\MockObject $node */ - $node = $this->createMock(Node::class); + $node = $this->createMock(Folder::class); $node->expects($this->any()) ->method('getId') ->willReturn($nodeId);