Skip to content

Commit da38cbf

Browse files
icewind1991AndyScherzinger
authored andcommitted
fix: rework move into object store to better preserve fileids
Signed-off-by: Robin Appelman <robin@icewind.nl>
1 parent 2dfdbe3 commit da38cbf

File tree

1 file changed

+55
-13
lines changed

1 file changed

+55
-13
lines changed

lib/private/Files/ObjectStore/ObjectStoreStorage.php

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -591,26 +591,68 @@ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $t
591591
if (!$sourceCacheEntry) {
592592
$sourceCacheEntry = $sourceCache->get($sourceInternalPath);
593593
}
594-
if ($sourceCacheEntry->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
595-
foreach ($sourceCache->getFolderContents($sourceInternalPath) as $child) {
596-
$this->moveFromStorage($sourceStorage, $child->getPath(), $targetInternalPath . '/' . $child->getName());
597-
}
594+
595+
$this->copyObjects($sourceStorage, $sourceCache, $sourceCacheEntry);
596+
if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) {
597+
/** @var ObjectStoreStorage $sourceStorage */
598+
$sourceStorage->setPreserveCacheOnDelete(true);
599+
}
600+
if ($sourceCacheEntry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE) {
598601
$sourceStorage->rmdir($sourceInternalPath);
599602
} else {
600-
// move the cache entry before the contents so that we have the correct fileid/urn for the target
601-
$this->getCache()->moveFromCache($sourceCache, $sourceInternalPath, $targetInternalPath);
602-
try {
603-
$this->writeStream($targetInternalPath, $sourceStorage->fopen($sourceInternalPath, 'r'), $sourceCacheEntry->getSize());
604-
} catch (\Exception $e) {
605-
// restore the cache entry
606-
$sourceCache->moveFromCache($this->getCache(), $targetInternalPath, $sourceInternalPath);
607-
throw $e;
608-
}
609603
$sourceStorage->unlink($sourceInternalPath);
610604
}
605+
if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) {
606+
/** @var ObjectStoreStorage $sourceStorage */
607+
$sourceStorage->setPreserveCacheOnDelete(false);
608+
}
609+
$this->getCache()->moveFromCache($sourceCache, $sourceInternalPath, $targetInternalPath);
610+
611611
return true;
612612
}
613613

614+
/**
615+
* Copy the object(s) of a file or folder into this storage, without touching the cache
616+
*/
617+
private function copyObjects(IStorage $sourceStorage, ICache $sourceCache, ICacheEntry $sourceCacheEntry) {
618+
$copiedFiles = [];
619+
try {
620+
foreach ($this->getAllChildObjects($sourceCache, $sourceCacheEntry) as $file) {
621+
$sourceStream = $sourceStorage->fopen($file->getPath(), 'r');
622+
if (!$sourceStream) {
623+
throw new \Exception("Failed to open source file {$file->getPath()} ({$file->getId()})");
624+
}
625+
$this->objectStore->writeObject($this->getURN($file->getId()), $sourceStream, $file->getMimeType());
626+
if (is_resource($sourceStream)) {
627+
fclose($sourceStream);
628+
}
629+
$copiedFiles[] = $file->getId();
630+
}
631+
} catch (\Exception $e) {
632+
foreach ($copiedFiles as $fileId) {
633+
try {
634+
$this->objectStore->deleteObject($this->getURN($fileId));
635+
} catch (\Exception $e) {
636+
// ignore
637+
}
638+
}
639+
throw $e;
640+
}
641+
}
642+
643+
/**
644+
* @return \Iterator<ICacheEntry>
645+
*/
646+
private function getAllChildObjects(ICache $cache, ICacheEntry $entry): \Iterator {
647+
if ($entry->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
648+
foreach ($cache->getFolderContentsById($entry->getId()) as $child) {
649+
yield from $this->getAllChildObjects($cache, $child);
650+
}
651+
} else {
652+
yield $entry;
653+
}
654+
}
655+
614656
public function copy($source, $target) {
615657
$source = $this->normalizePath($source);
616658
$target = $this->normalizePath($target);

0 commit comments

Comments
 (0)