From 6f962c75d4c90a6277425848707c72df4cb09831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Mon, 9 Sep 2024 13:07:14 +0200 Subject: [PATCH 1/2] fix: Fix copying or moving from shared groupfolders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When copying or moving between two local storages the source path (on disk) to copy or move from is got from the unjailed path of the source storage. However, if the source storage has more than one jail getting the unjailed path resolves the most external jail, but the source path needs to be got from the most internal jail instead (the one closer to the local storage). This can happen, for example, with a shared groupfolder: in that case there is an external jail for the shared storage, and one internal jail for the groupfolder storage wrapped by the shared storage. Signed-off-by: Daniel Calviño Sánchez --- lib/private/Files/Storage/Local.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php index 201f6d7daf4c4..ca2113add75d0 100644 --- a/lib/private/Files/Storage/Local.php +++ b/lib/private/Files/Storage/Local.php @@ -605,11 +605,13 @@ private function canDoCrossStorageMove(IStorage $sourceStorage) { */ public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) { if ($this->canDoCrossStorageMove($sourceStorage)) { - if ($sourceStorage->instanceOfStorage(Jail::class)) { + // resolve any jailed paths + while ($sourceStorage->instanceOfStorage(Jail::class)) { /** * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage */ $sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath); + $sourceStorage = $sourceStorage->getUnjailedStorage(); } /** * @var \OC\Files\Storage\Local $sourceStorage @@ -629,11 +631,13 @@ public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $t */ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { if ($this->canDoCrossStorageMove($sourceStorage)) { - if ($sourceStorage->instanceOfStorage(Jail::class)) { + // resolve any jailed paths + while ($sourceStorage->instanceOfStorage(Jail::class)) { /** * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage */ $sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath); + $sourceStorage = $sourceStorage->getUnjailedStorage(); } /** * @var \OC\Files\Storage\Local $sourceStorage From a61d2ab4c4795f8e8df2b0a6c7baa844296ddc18 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Oct 2024 17:00:53 +0200 Subject: [PATCH 2/2] test: add test for nested jail cross-storage move Signed-off-by: Robin Appelman --- tests/lib/Files/Storage/LocalTest.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/lib/Files/Storage/LocalTest.php b/tests/lib/Files/Storage/LocalTest.php index 1190a2b2da043..adee2e8253d01 100644 --- a/tests/lib/Files/Storage/LocalTest.php +++ b/tests/lib/Files/Storage/LocalTest.php @@ -22,6 +22,8 @@ namespace Test\Files\Storage; +use OC\Files\Storage\Wrapper\Jail; + /** * Class LocalTest * @@ -150,4 +152,25 @@ public function testUnavailableNonExternal() { // no exception thrown $this->assertNotNull($this->instance); } + + public function testMoveNestedJail(): void { + $this->instance->mkdir('foo'); + $this->instance->mkdir('foo/bar'); + $this->instance->mkdir('target'); + $this->instance->file_put_contents('foo/bar/file.txt', 'foo'); + $jail1 = new Jail([ + 'storage' => $this->instance, + 'root' => 'foo' + ]); + $jail2 = new Jail([ + 'storage' => $jail1, + 'root' => 'bar' + ]); + $jail3 = new Jail([ + 'storage' => $this->instance, + 'root' => 'target' + ]); + $jail3->moveFromStorage($jail2, 'file.txt', 'file.txt'); + $this->assertTrue($this->instance->file_exists('target/file.txt')); + } }