@@ -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