From 34ce236290f8297bb29b02c19e2e3f205dbfbea2 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Wed, 22 Jul 2026 13:29:39 +0200 Subject: [PATCH 1/4] chore: Bump 3rdparty version for new sabre dependencies Signed-off-by: Carl Schwan --- 3rdparty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty b/3rdparty index ec0e643aab90b..37a4d20db5cad 160000 --- a/3rdparty +++ b/3rdparty @@ -1 +1 @@ -Subproject commit ec0e643aab90b8366fe1267b7068ed6e2b95532c +Subproject commit 37a4d20db5cad99082d636bab63dc1c8f4c481a6 From 451f68cec7f690a0fa9b66277c81831c5e91fe3d Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Wed, 22 Jul 2026 13:21:19 +0200 Subject: [PATCH 2/4] fix: Adapt Directory::copyInto signature to new version of sabre/dav Signed-off-by: Carl Schwan --- apps/dav/lib/Connector/Sabre/Directory.php | 2 +- apps/dav/lib/Connector/Sabre/ObjectTree.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php index 1634c512804b3..da26c9b475616 100644 --- a/apps/dav/lib/Connector/Sabre/Directory.php +++ b/apps/dav/lib/Connector/Sabre/Directory.php @@ -472,7 +472,7 @@ public function moveInto($targetName, $fullSourcePath, INode $sourceNode) { } #[\Override] - public function copyInto($targetName, $sourcePath, INode $sourceNode) { + public function copyInto($targetName, $sourcePath, INode $sourceNode, int $depth): bool { if ($sourceNode instanceof File || $sourceNode instanceof Directory) { try { $destinationPath = $this->getPath() . '/' . $targetName; diff --git a/apps/dav/lib/Connector/Sabre/ObjectTree.php b/apps/dav/lib/Connector/Sabre/ObjectTree.php index 0feb7032b8507..3e9140576a35d 100644 --- a/apps/dav/lib/Connector/Sabre/ObjectTree.php +++ b/apps/dav/lib/Connector/Sabre/ObjectTree.php @@ -21,6 +21,7 @@ use OCP\Files\StorageInvalidException; use OCP\Files\StorageNotAvailableException; use OCP\Lock\LockedException; +use Sabre\DAV\Server; class ObjectTree extends CachingTree { @@ -154,7 +155,7 @@ public function getNodeForPath($path) { * @return void */ #[\Override] - public function copy($sourcePath, $destinationPath) { + public function copy($sourcePath, $destinationPath, int $depth = Server::DEPTH_INFINITY): void { if (!$this->fileView) { throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); } From 7a9561f10bc4b4abb852ba1401df05a1282be5da Mon Sep 17 00:00:00 2001 From: Daniel Kesselberg Date: Fri, 24 Jul 2026 19:15:08 +0200 Subject: [PATCH 3/4] test: update PRODID fixtures for sabre/vobject 4.6.1 Assisted-by: ClaudeCode:claude-sonnet-5 Signed-off-by: Daniel Kesselberg --- apps/dav/lib/ExampleContentFiles/exampleContact.vcf | 2 +- .../unit/test_fixtures/example-event-default-expected.ics | 2 +- tests/data/ics/event-builder-complete.ics | 2 +- tests/data/ics/event-builder-without-attendees.ics | 2 +- tests/data/ics/free-busy-request.ics | 2 +- tests/lib/Calendar/ManagerTest.php | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/dav/lib/ExampleContentFiles/exampleContact.vcf b/apps/dav/lib/ExampleContentFiles/exampleContact.vcf index c58c949d0db6c..95c3310052d0c 100644 --- a/apps/dav/lib/ExampleContentFiles/exampleContact.vcf +++ b/apps/dav/lib/ExampleContentFiles/exampleContact.vcf @@ -1,6 +1,6 @@ BEGIN:VCARD VERSION:3.0 -PRODID:-//Sabre//Sabre VObject 4.5.6//EN +PRODID:-//Sabre//Sabre VObject 4.6.1//EN UID:cffff367-4580-4e01-8b6d-f91e95ce7e92 FN:Leon Green ADR;TYPE=HOME:;;123 Street Street;City;State;;Country diff --git a/apps/dav/tests/unit/test_fixtures/example-event-default-expected.ics b/apps/dav/tests/unit/test_fixtures/example-event-default-expected.ics index 09606ca5ee4d9..4d523f6d64b67 100644 --- a/apps/dav/tests/unit/test_fixtures/example-event-default-expected.ics +++ b/apps/dav/tests/unit/test_fixtures/example-event-default-expected.ics @@ -1,6 +1,6 @@ BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Sabre//Sabre VObject 4.5.6//EN +PRODID:-//Sabre//Sabre VObject 4.6.1//EN CALSCALE:GREGORIAN BEGIN:VEVENT UID:RANDOM-UID diff --git a/tests/data/ics/event-builder-complete.ics b/tests/data/ics/event-builder-complete.ics index 65fe8e6cf1328..29d5398b29cb7 100644 --- a/tests/data/ics/event-builder-complete.ics +++ b/tests/data/ics/event-builder-complete.ics @@ -1,6 +1,6 @@ BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Sabre//Sabre VObject 4.5.6//EN +PRODID:-//Sabre//Sabre VObject 4.6.1//EN CALSCALE:GREGORIAN BEGIN:VEVENT UID:event-uid-123 diff --git a/tests/data/ics/event-builder-without-attendees.ics b/tests/data/ics/event-builder-without-attendees.ics index fad48caa3a9e8..1823117a2b43c 100644 --- a/tests/data/ics/event-builder-without-attendees.ics +++ b/tests/data/ics/event-builder-without-attendees.ics @@ -1,6 +1,6 @@ BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Sabre//Sabre VObject 4.5.6//EN +PRODID:-//Sabre//Sabre VObject 4.6.1//EN CALSCALE:GREGORIAN BEGIN:VEVENT UID:event-uid-123 diff --git a/tests/data/ics/free-busy-request.ics b/tests/data/ics/free-busy-request.ics index dd01d35b67131..c45f94bb01c27 100644 --- a/tests/data/ics/free-busy-request.ics +++ b/tests/data/ics/free-busy-request.ics @@ -1,6 +1,6 @@ BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Sabre//Sabre VObject 4.5.6//EN +PRODID:-//Sabre//Sabre VObject 4.6.1//EN CALSCALE:GREGORIAN METHOD:REQUEST BEGIN:VFREEBUSY diff --git a/tests/lib/Calendar/ManagerTest.php b/tests/lib/Calendar/ManagerTest.php index ce7ce113ce8bd..007a492e4bdf2 100644 --- a/tests/lib/Calendar/ManagerTest.php +++ b/tests/lib/Calendar/ManagerTest.php @@ -981,7 +981,7 @@ private function getFreeBusyResponse(): string { 2.0;Success BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Sabre//Sabre VObject 4.5.6//EN +PRODID:-//Sabre//Sabre VObject 4.6.1//EN CALSCALE:GREGORIAN METHOD:REPLY BEGIN:VFREEBUSY @@ -1004,7 +1004,7 @@ private function getFreeBusyResponse(): string { 2.0;Success BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Sabre//Sabre VObject 4.5.6//EN +PRODID:-//Sabre//Sabre VObject 4.6.1//EN CALSCALE:GREGORIAN METHOD:REPLY BEGIN:VFREEBUSY @@ -1025,7 +1025,7 @@ private function getFreeBusyResponse(): string { 2.0;Success BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Sabre//Sabre VObject 4.5.6//EN +PRODID:-//Sabre//Sabre VObject 4.6.1//EN CALSCALE:GREGORIAN METHOD:REPLY BEGIN:VFREEBUSY From a3e12d41e3c43e373ddb5e8dcb3cd41977f3bf41 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Fri, 31 Jul 2026 12:11:14 +0200 Subject: [PATCH 4/4] feat: Add minimal support for COPY operation with DEPTH Signed-off-by: Carl Schwan --- apps/dav/lib/Connector/Sabre/Directory.php | 5 +++++ apps/dav/lib/Connector/Sabre/ObjectTree.php | 24 ++++++++++----------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php index da26c9b475616..6bec57c50fbb3 100644 --- a/apps/dav/lib/Connector/Sabre/Directory.php +++ b/apps/dav/lib/Connector/Sabre/Directory.php @@ -473,6 +473,11 @@ public function moveInto($targetName, $fullSourcePath, INode $sourceNode) { #[\Override] public function copyInto($targetName, $sourcePath, INode $sourceNode, int $depth): bool { + if ($sourceNode instanceof Directory && $depth !== \Sabre\DAV\Server::DEPTH_INFINITY) { + // Fall back to sabre default copyNode() implementation + return false; + } + if ($sourceNode instanceof File || $sourceNode instanceof Directory) { try { $destinationPath = $this->getPath() . '/' . $targetName; diff --git a/apps/dav/lib/Connector/Sabre/ObjectTree.php b/apps/dav/lib/Connector/Sabre/ObjectTree.php index 3e9140576a35d..96121a1450f4b 100644 --- a/apps/dav/lib/Connector/Sabre/ObjectTree.php +++ b/apps/dav/lib/Connector/Sabre/ObjectTree.php @@ -21,19 +21,12 @@ use OCP\Files\StorageInvalidException; use OCP\Files\StorageNotAvailableException; use OCP\Lock\LockedException; +use Sabre\DAV\INode; use Sabre\DAV\Server; class ObjectTree extends CachingTree { - - /** - * @var View - */ - protected $fileView; - - /** - * @var IMountManager - */ - protected $mountManager; + protected View $fileView; + protected IMountManager $mountManager; /** * Creates the object @@ -56,14 +49,13 @@ public function init(\Sabre\DAV\INode $rootNode, View $view, IMountManager $moun * Returns the INode object for the requested path * * @param string $path - * @return \Sabre\DAV\INode * @throws InvalidPath * @throws \Sabre\DAV\Exception\Locked * @throws \Sabre\DAV\Exception\NotFound * @throws \Sabre\DAV\Exception\ServiceUnavailable */ #[\Override] - public function getNodeForPath($path) { + public function getNodeForPath($path): INode { if (!$this->fileView) { throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); } @@ -171,7 +163,13 @@ public function copy($sourcePath, $destinationPath, int $depth = Server::DEPTH_I } // this will trigger existence check - $this->getNodeForPath($sourcePath); + $sourceNode = $this->getNodeForPath($sourcePath); + + if ($sourceNode instanceof Directory && $depth !== Server::DEPTH_INFINITY) { + // Fallback to sabre slow default implementation with $depth support. + parent::copy($sourcePath, $destinationPath, $depth); + return; + } [$destinationDir, $destinationName] = \Sabre\Uri\split($destinationPath); try {