From 320d5154fc75ebbfba92dc49aea1336756825dd3 Mon Sep 17 00:00:00 2001 From: lazerg Date: Sat, 31 Oct 2026 13:04:43 +0500 Subject: [PATCH] fix(dav): return NotFound when an ancestor's file info is unavailable Assisted-by: ClaudeCode:claude-sonnet-5-5 Signed-off-by: lazerg --- apps/dav/lib/Connector/Sabre/Directory.php | 4 ++ .../unit/Connector/Sabre/DirectoryTest.php | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php index 20c1fade100cf..b55dbac0a1a93 100644 --- a/apps/dav/lib/Connector/Sabre/Directory.php +++ b/apps/dav/lib/Connector/Sabre/Directory.php @@ -567,6 +567,10 @@ public function getNodeForPath($path): INode { // to the node API /** @psalm-suppress InternalMethod */ $info = $this->fileView->getFileInfo($scanPath, false); + if (!$info) { + throw new \Sabre\DAV\Exception\NotFound('File with name ' . $destinationPath + . ' could not be located'); + } $directory = new Directory($this->fileView, $info, $this->tree, $this->shareManager); $readable = $directory->getNode()->isReadable(); if (!$readable) { diff --git a/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php b/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php index cbd3891f7aea0..17dd741cc0d4c 100644 --- a/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php @@ -424,6 +424,50 @@ public function testGetNodeForPathFailsWithNoReadPermissionsForParent(): void { $dir->getNodeForPath('/my/deep/folder/'); } + public function testGetNodeForPathFailsWithNoReadPermissionsForMissingParentInfo(): void { + $directoryNode = $this->createMock(Folder::class); + $pathNode = $this->createMock(Folder::class); + $storage = $this->createMock(IStorage::class); + + $directoryNode->expects($this->once()) + ->method('getStorage') + ->willReturn($storage); + $storage->expects($this->once()) + ->method('instanceOfStorage') + ->willReturn(false); + + $directoryNode->expects($this->once()) + ->method('isReadable') + ->willReturn(true); + $directoryNode->expects($this->once()) + ->method('getPath') + ->willReturn('/admin/files/'); + $directoryNode->expects($this->once()) + ->method('get') + ->willReturn($pathNode); + + $pathNode->expects($this->once()) + ->method('getPath') + ->willReturn('/admin/files/my/deep/folder/'); + $pathNode->expects($this->once()) + ->method('getMimetype') + ->willReturn(FileInfo::MIMETYPE_FOLDER); + + $this->view->method('getRelativePath') + ->willReturnCallback(function ($path) { + return str_replace('/admin/files/', '', $path); + }); + + $this->view->expects($this->once()) + ->method('getFileInfo') + ->willReturn(false); + + $this->expectException(NotFound::class); + + $dir = new Directory($this->view, $directoryNode); + $dir->getNodeForPath('/my/deep/folder/'); + } + public function testGetNodeForPathFailsWithNoReadPermissionsForPath(): void { $this->view ->method('getRelativePath')