aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/private/Files/ObjectStore/Azure.php4
-rw-r--r--lib/private/Files/ObjectStore/ObjectStoreStorage.php64
-rw-r--r--lib/private/Files/ObjectStore/S3ObjectTrait.php4
-rw-r--r--lib/private/Files/ObjectStore/StorageObjectStore.php4
-rw-r--r--lib/private/Files/ObjectStore/Swift.php12
-rw-r--r--lib/public/Files/ObjectStore/IObjectStore.php8
-rw-r--r--tests/lib/Files/ObjectStore/FailDeleteObjectStore.php4
-rw-r--r--tests/lib/Files/ObjectStore/FailWriteObjectStore.php4
-rw-r--r--tests/lib/Files/ObjectStore/ObjectStoreTest.php16
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 e675064eb1f..e855c166612 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
*/
@@ -319,7 +324,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
} else {
return false;
}
- // no break
+ // no break
case 'w':
case 'wb':
case 'w+':
@@ -474,7 +479,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;
});
@@ -523,4 +528,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 a390c6b4c7d..80b8a6f132d 100644
--- a/lib/private/Files/ObjectStore/S3ObjectTrait.php
+++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php
@@ -124,4 +124,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 5ee924c9de6..1b0888b0700 100644
--- a/lib/private/Files/ObjectStore/Swift.php
+++ b/lib/private/Files/ObjectStore/Swift.php
@@ -87,13 +87,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,
]);
}
}
@@ -114,7 +114,7 @@ class Swift implements IObjectStore {
'stream' => true,
'headers' => [
'X-Auth-Token' => $tokenId,
- 'Cache-Control' => 'no-cache'
+ 'Cache-Control' => 'no-cache',
],
]
);
@@ -149,4 +149,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')));
+ }
}