aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2024-09-26 16:28:59 +0200
committerAndy Scherzinger <info@andy-scherzinger.de>2025-02-13 17:31:51 +0100
commitda334737e4092aab89b44d2d9ec6613b652741e5 (patch)
treef20222683e76331a7ad9fd43efbeddc47153f836
parent5a772da95e5aa3c5167a9b94665c3461175c1417 (diff)
downloadnextcloud-server-da334737e4092aab89b44d2d9ec6613b652741e5.tar.gz
nextcloud-server-da334737e4092aab89b44d2d9ec6613b652741e5.zip
fix: rework move into object store to better preserve fileids
Signed-off-by: Robin Appelman <robin@icewind.nl>
-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 aa07e91fa80..acf0dd492bc 100644
--- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php
+++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
@@ -610,32 +610,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) {
$source = $this->normalizePath($source);
$target = $this->normalizePath($target);