aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2024-09-26 16:28:59 +0200
committerRobin Appelman <robin@icewind.nl>2024-09-27 14:46:08 +0200
commit3e12e1e7898903f6ef26f21db8bc21e7b29f0868 (patch)
tree74378c7fe01a1d86c43a48d708963757c3008972 /lib/private
parentf8a59b56b4791413b5ac36459e8b92ed6017b19b (diff)
downloadnextcloud-server-3e12e1e7898903f6ef26f21db8bc21e7b29f0868.tar.gz
nextcloud-server-3e12e1e7898903f6ef26f21db8bc21e7b29f0868.zip
fix: rework move into object store to better preserve fileidsreadd-object-store-phpunit
Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/Files/ObjectStore/ObjectStoreStorage.php74
1 files changed, 55 insertions, 19 deletions
diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
index ab4852f9c85..5f568a3aba3 100644
--- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php
+++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
@@ -601,32 +601,68 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
if (!$sourceCacheEntry) {
$sourceCacheEntry = $sourceCache->get($sourceInternalPath);
}
- if ($sourceCacheEntry->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
- $this->mkdir($targetInternalPath);
- foreach ($sourceCache->getFolderContentsById($sourceCacheEntry->getId()) as $child) {
- $this->moveFromStorage($sourceStorage, $child->getPath(), $targetInternalPath . '/' . $child->getName(), $child);
- }
+
+ $this->copyObjects($sourceStorage, $sourceCache, $sourceCacheEntry);
+ if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) {
+ /** @var ObjectStoreStorage $sourceStorage */
+ $sourceStorage->setPreserveCacheOnDelete(true);
+ }
+ if ($sourceCacheEntry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE) {
$sourceStorage->rmdir($sourceInternalPath);
- $sourceStorage->getCache()->remove($sourceInternalPath);
} else {
- $sourceStream = $sourceStorage->fopen($sourceInternalPath, 'r');
- if (!$sourceStream) {
- return false;
- }
- // move the cache entry before the contents so that we have the correct fileid/urn for the target
- $this->getCache()->moveFromCache($sourceCache, $sourceInternalPath, $targetInternalPath);
- try {
- $this->writeStream($targetInternalPath, $sourceStream, $sourceCacheEntry->getSize());
- } catch (\Exception $e) {
- // restore the cache entry
- $sourceCache->moveFromCache($this->getCache(), $targetInternalPath, $sourceInternalPath);
- throw $e;
- }
$sourceStorage->unlink($sourceInternalPath);
}
+ if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) {
+ /** @var ObjectStoreStorage $sourceStorage */
+ $sourceStorage->setPreserveCacheOnDelete(false);
+ }
+ $this->getCache()->moveFromCache($sourceCache, $sourceInternalPath, $targetInternalPath);
+
return true;
}
+ /**
+ * Copy the object(s) of a file or folder into this storage, without touching the cache
+ */
+ private function copyObjects(IStorage $sourceStorage, ICache $sourceCache, ICacheEntry $sourceCacheEntry) {
+ $copiedFiles = [];
+ try {
+ foreach ($this->getAllChildObjects($sourceCache, $sourceCacheEntry) as $file) {
+ $sourceStream = $sourceStorage->fopen($file->getPath(), 'r');
+ if (!$sourceStream) {
+ throw new \Exception("Failed to open source file {$file->getPath()} ({$file->getId()})");
+ }
+ $this->objectStore->writeObject($this->getURN($file->getId()), $sourceStream, $file->getMimeType());
+ if (is_resource($sourceStream)) {
+ fclose($sourceStream);
+ }
+ $copiedFiles[] = $file->getId();
+ }
+ } catch (\Exception $e) {
+ foreach ($copiedFiles as $fileId) {
+ try {
+ $this->objectStore->deleteObject($this->getURN($fileId));
+ } catch (\Exception $e) {
+ // ignore
+ }
+ }
+ throw $e;
+ }
+ }
+
+ /**
+ * @return \Iterator<ICacheEntry>
+ */
+ private function getAllChildObjects(ICache $cache, ICacheEntry $entry): \Iterator {
+ if ($entry->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
+ foreach ($cache->getFolderContentsById($entry->getId()) as $child) {
+ yield from $this->getAllChildObjects($cache, $child);
+ }
+ } else {
+ yield $entry;
+ }
+ }
+
public function copy($source, $target): bool {
$source = $this->normalizePath($source);
$target = $this->normalizePath($target);