mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
fix: rework move into object store to better preserve fileids
Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
parent
f8a59b56b4
commit
3e12e1e789
1 changed files with 55 additions and 19 deletions
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue