diff options
author | Morris Jobke <hey@morrisjobke.de> | 2021-01-07 13:28:38 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-07 13:28:38 +0100 |
commit | 57e165c244cda90f78ee59c293995ae9eeb5ce11 (patch) | |
tree | 60b11e2d64dc13b45632c98c19b283e9e4bab5b0 | |
parent | 3f8024932a5e8fc7c0f5eecabb6a8d618a12f70c (diff) | |
parent | dedff0facb10e27f5243b4e495a4e31ca7ec8456 (diff) | |
download | nextcloud-server-57e165c244cda90f78ee59c293995ae9eeb5ce11.tar.gz nextcloud-server-57e165c244cda90f78ee59c293995ae9eeb5ce11.zip |
Merge pull request #24593 from nextcloud/backport/23912/stable19
[stable19] use in objectstore copy
-rw-r--r-- | lib/private/Files/ObjectStore/Azure.php | 4 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/ObjectStoreStorage.php | 64 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/S3ObjectTrait.php | 4 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/StorageObjectStore.php | 4 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/Swift.php | 12 | ||||
-rw-r--r-- | lib/public/Files/ObjectStore/IObjectStore.php | 8 | ||||
-rw-r--r-- | tests/lib/Files/ObjectStore/FailDeleteObjectStore.php | 4 | ||||
-rw-r--r-- | tests/lib/Files/ObjectStore/FailWriteObjectStore.php | 4 | ||||
-rw-r--r-- | tests/lib/Files/ObjectStore/ObjectStoreTest.php | 16 |
9 files changed, 115 insertions, 5 deletions
diff --git a/lib/private/Files/ObjectStore/Azure.php b/lib/private/Files/ObjectStore/Azure.php index 0b65a6b80e5..2ef13d60c56 100644 --- a/lib/private/Files/ObjectStore/Azure.php +++ b/lib/private/Files/ObjectStore/Azure.php @@ -130,4 +130,8 @@ class Azure implements IObjectStore { } } } + + public function copyObject($from, $to) { + $this->getBlobClient()->copyBlob($this->containerName, $to, $this->containerName, $from); + } } diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index 3a48efcb31e..060a249b9c6 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -33,10 +33,15 @@ use Icewind\Streams\CallbackWrapper; use Icewind\Streams\CountWrapper; use Icewind\Streams\IteratorDirectory; use OC\Files\Cache\CacheEntry; +use OC\Files\Storage\PolyFill\CopyDirectory; +use OCP\Files\Cache\ICacheEntry; +use OCP\Files\FileInfo; use OCP\Files\NotFoundException; use OCP\Files\ObjectStore\IObjectStore; class ObjectStoreStorage extends \OC\Files\Storage\Common { + use CopyDirectory; + /** * @var \OCP\Files\ObjectStore\IObjectStore $objectStore */ @@ -309,7 +314,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { } else { return false; } - // no break + // no break case 'w': case 'wb': case 'w+': @@ -464,7 +469,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { if ($size === null) { $countStream = CountWrapper::wrap($stream, function ($writtenSize) use ($fileId, &$size) { $this->getCache()->update($fileId, [ - 'size' => $writtenSize + 'size' => $writtenSize, ]); $size = $writtenSize; }); @@ -513,4 +518,59 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { public function getObjectStore(): IObjectStore { return $this->objectStore; } + + public function copy($path1, $path2) { + $path1 = $this->normalizePath($path1); + $path2 = $this->normalizePath($path2); + + $cache = $this->getCache(); + $sourceEntry = $cache->get($path1); + if (!$sourceEntry) { + throw new NotFoundException('Source object not found'); + } + + $this->copyInner($sourceEntry, $path2); + + return true; + } + + private function copyInner(ICacheEntry $sourceEntry, string $to) { + $cache = $this->getCache(); + + if ($sourceEntry->getMimeType() === FileInfo::MIMETYPE_FOLDER) { + if ($cache->inCache($to)) { + $cache->remove($to); + } + $this->mkdir($to); + + foreach ($cache->getFolderContentsById($sourceEntry->getId()) as $child) { + $this->copyInner($child, $to . '/' . $child->getName()); + } + } else { + $this->copyFile($sourceEntry, $to); + } + } + + private function copyFile(ICacheEntry $sourceEntry, string $to) { + $cache = $this->getCache(); + + $sourceUrn = $this->getURN($sourceEntry->getId()); + + $cache->copyFromCache($cache, $sourceEntry, $to); + $targetEntry = $cache->get($to); + + if (!$targetEntry) { + throw new \Exception('Target not in cache after copy'); + } + + $targetUrn = $this->getURN($targetEntry->getId()); + + try { + $this->objectStore->copyObject($sourceUrn, $targetUrn); + } catch (\Exception $e) { + $cache->remove($to); + + throw $e; + } + } } diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php index d7c878178d2..49284533723 100644 --- a/lib/private/Files/ObjectStore/S3ObjectTrait.php +++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php @@ -123,4 +123,8 @@ trait S3ObjectTrait { public function objectExists($urn) { return $this->getConnection()->doesObjectExist($this->bucket, $urn); } + + public function copyObject($from, $to) { + $this->getConnection()->copy($this->getBucket(), $from, $this->getBucket(), $to); + } } diff --git a/lib/private/Files/ObjectStore/StorageObjectStore.php b/lib/private/Files/ObjectStore/StorageObjectStore.php index a7551385b34..acf46758956 100644 --- a/lib/private/Files/ObjectStore/StorageObjectStore.php +++ b/lib/private/Files/ObjectStore/StorageObjectStore.php @@ -93,4 +93,8 @@ class StorageObjectStore implements IObjectStore { public function objectExists($urn) { return $this->storage->file_exists($urn); } + + public function copyObject($from, $to) { + $this->storage->copy($from, $to); + } } diff --git a/lib/private/Files/ObjectStore/Swift.php b/lib/private/Files/ObjectStore/Swift.php index 87347c3f71b..ba5eb9e37ff 100644 --- a/lib/private/Files/ObjectStore/Swift.php +++ b/lib/private/Files/ObjectStore/Swift.php @@ -86,13 +86,13 @@ class Swift implements IObjectStore { if (filesize($tmpFile) < SWIFT_SEGMENT_SIZE) { $this->getContainer()->createObject([ 'name' => $urn, - 'stream' => stream_for($handle) + 'stream' => stream_for($handle), ]); } else { $this->getContainer()->createLargeObject([ 'name' => $urn, 'stream' => stream_for($handle), - 'segmentSize' => SWIFT_SEGMENT_SIZE + 'segmentSize' => SWIFT_SEGMENT_SIZE, ]); } } @@ -113,7 +113,7 @@ class Swift implements IObjectStore { 'stream' => true, 'headers' => [ 'X-Auth-Token' => $tokenId, - 'Cache-Control' => 'no-cache' + 'Cache-Control' => 'no-cache', ], ] ); @@ -148,4 +148,10 @@ class Swift implements IObjectStore { public function objectExists($urn) { return $this->getContainer()->objectExists($urn); } + + public function copyObject($from, $to) { + $this->getContainer()->getObject($from)->copy([ + 'destination' => $this->getContainer()->name . '/' . $to + ]); + } } diff --git a/lib/public/Files/ObjectStore/IObjectStore.php b/lib/public/Files/ObjectStore/IObjectStore.php index 4925959d6c5..e9d948682f8 100644 --- a/lib/public/Files/ObjectStore/IObjectStore.php +++ b/lib/public/Files/ObjectStore/IObjectStore.php @@ -73,4 +73,12 @@ interface IObjectStore { * @since 16.0.0 */ public function objectExists($urn); + + /** + * @param string $from the unified resource name used to identify the source object + * @param string $to the unified resource name used to identify the target object + * @return void + * @since 21.0.0 + */ + public function copyObject($from, $to); } diff --git a/tests/lib/Files/ObjectStore/FailDeleteObjectStore.php b/tests/lib/Files/ObjectStore/FailDeleteObjectStore.php index 1a3477090b9..c755657faff 100644 --- a/tests/lib/Files/ObjectStore/FailDeleteObjectStore.php +++ b/tests/lib/Files/ObjectStore/FailDeleteObjectStore.php @@ -51,4 +51,8 @@ class FailDeleteObjectStore implements IObjectStore { public function objectExists($urn) { return $this->objectStore->objectExists($urn); } + + public function copyObject($from, $to) { + $this->objectStore->copyObject($from, $to); + } } diff --git a/tests/lib/Files/ObjectStore/FailWriteObjectStore.php b/tests/lib/Files/ObjectStore/FailWriteObjectStore.php index ad2350ea36b..b9c8751fda3 100644 --- a/tests/lib/Files/ObjectStore/FailWriteObjectStore.php +++ b/tests/lib/Files/ObjectStore/FailWriteObjectStore.php @@ -52,4 +52,8 @@ class FailWriteObjectStore implements IObjectStore { public function objectExists($urn) { return $this->objectStore->objectExists($urn); } + + public function copyObject($from, $to) { + $this->objectStore->copyObject($from, $to); + } } diff --git a/tests/lib/Files/ObjectStore/ObjectStoreTest.php b/tests/lib/Files/ObjectStore/ObjectStoreTest.php index 9300a9bdef6..4ec44eb410d 100644 --- a/tests/lib/Files/ObjectStore/ObjectStoreTest.php +++ b/tests/lib/Files/ObjectStore/ObjectStoreTest.php @@ -108,4 +108,20 @@ abstract class ObjectStoreTest extends TestCase { $this->assertFalse($instance->objectExists('2')); } + + public function testCopy() { + $stream = $this->stringToStream('foobar'); + + $instance = $this->getInstance(); + + $instance->writeObject('source', $stream); + + $this->assertFalse($instance->objectExists('target')); + + $instance->copyObject('source', 'target'); + + $this->assertTrue($instance->objectExists('target')); + + $this->assertEquals('foobar', stream_get_contents($instance->readObject('target'))); + } } |