Skip to content

Commit

Permalink
fix: rework move into object store to better preserve fileids
Browse files Browse the repository at this point in the history
Signed-off-by: Robin Appelman <[email protected]>
  • Loading branch information
icewind1991 authored and artonge committed Nov 6, 2024
1 parent 71c3b50 commit 4c95ba9
Showing 1 changed file with 55 additions and 13 deletions.
68 changes: 55 additions & 13 deletions lib/private/Files/ObjectStore/ObjectStoreStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -591,26 +591,68 @@ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $t
if (!$sourceCacheEntry) {
$sourceCacheEntry = $sourceCache->get($sourceInternalPath);
}
if ($sourceCacheEntry->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
foreach ($sourceCache->getFolderContents($sourceInternalPath) as $child) {
$this->moveFromStorage($sourceStorage, $child->getPath(), $targetInternalPath . '/' . $child->getName());
}

$this->copyObjects($sourceStorage, $sourceCache, $sourceCacheEntry);
if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) {
/** @var ObjectStoreStorage $sourceStorage */
$sourceStorage->setPreserveCacheOnDelete(true);

Check failure

Code scanning / Psalm

UndefinedMethod Error

Method OC\Files\ObjectStore\ObjectStoreStorage::setPreserveCacheOnDelete does not exist

Check failure on line 598 in lib/private/Files/ObjectStore/ObjectStoreStorage.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedMethod

lib/private/Files/ObjectStore/ObjectStoreStorage.php:598:20: UndefinedMethod: Method OC\Files\ObjectStore\ObjectStoreStorage::setPreserveCacheOnDelete does not exist (see https://psalm.dev/022)
}
if ($sourceCacheEntry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE) {
$sourceStorage->rmdir($sourceInternalPath);
} else {
// 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, $sourceStorage->fopen($sourceInternalPath, 'r'), $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);

Check failure

Code scanning / Psalm

UndefinedMethod Error

Method OC\Files\ObjectStore\ObjectStoreStorage::setPreserveCacheOnDelete does not exist

Check failure on line 607 in lib/private/Files/ObjectStore/ObjectStoreStorage.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedMethod

lib/private/Files/ObjectStore/ObjectStoreStorage.php:607:20: UndefinedMethod: Method OC\Files\ObjectStore\ObjectStoreStorage::setPreserveCacheOnDelete does not exist (see https://psalm.dev/022)
}
$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);
Expand Down

0 comments on commit 4c95ba9

Please sign in to comment.