@@ -614,26 +614,68 @@ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $t
614614 if (!$ sourceCacheEntry ) {
615615 $ sourceCacheEntry = $ sourceCache ->get ($ sourceInternalPath );
616616 }
617- if ($ sourceCacheEntry ->getMimeType () === FileInfo::MIMETYPE_FOLDER ) {
618- foreach ($ sourceCache ->getFolderContents ($ sourceInternalPath ) as $ child ) {
619- $ this ->moveFromStorage ($ sourceStorage , $ child ->getPath (), $ targetInternalPath . '/ ' . $ child ->getName ());
620- }
617+
618+ $ this ->copyObjects ($ sourceStorage , $ sourceCache , $ sourceCacheEntry );
619+ if ($ sourceStorage ->instanceOfStorage (ObjectStoreStorage::class)) {
620+ /** @var ObjectStoreStorage $sourceStorage */
621+ $ sourceStorage ->setPreserveCacheOnDelete (true );
622+ }
623+ if ($ sourceCacheEntry ->getMimeType () === ICacheEntry::DIRECTORY_MIMETYPE ) {
621624 $ sourceStorage ->rmdir ($ sourceInternalPath );
622625 } else {
623- // move the cache entry before the contents so that we have the correct fileid/urn for the target
624- $ this ->getCache ()->moveFromCache ($ sourceCache , $ sourceInternalPath , $ targetInternalPath );
625- try {
626- $ this ->writeStream ($ targetInternalPath , $ sourceStorage ->fopen ($ sourceInternalPath , 'r ' ), $ sourceCacheEntry ->getSize ());
627- } catch (\Exception $ e ) {
628- // restore the cache entry
629- $ sourceCache ->moveFromCache ($ this ->getCache (), $ targetInternalPath , $ sourceInternalPath );
630- throw $ e ;
631- }
632626 $ sourceStorage ->unlink ($ sourceInternalPath );
633627 }
628+ if ($ sourceStorage ->instanceOfStorage (ObjectStoreStorage::class)) {
629+ /** @var ObjectStoreStorage $sourceStorage */
630+ $ sourceStorage ->setPreserveCacheOnDelete (false );
631+ }
632+ $ this ->getCache ()->moveFromCache ($ sourceCache , $ sourceInternalPath , $ targetInternalPath );
633+
634634 return true ;
635635 }
636636
637+ /**
638+ * Copy the object(s) of a file or folder into this storage, without touching the cache
639+ */
640+ private function copyObjects (IStorage $ sourceStorage , ICache $ sourceCache , ICacheEntry $ sourceCacheEntry ) {
641+ $ copiedFiles = [];
642+ try {
643+ foreach ($ this ->getAllChildObjects ($ sourceCache , $ sourceCacheEntry ) as $ file ) {
644+ $ sourceStream = $ sourceStorage ->fopen ($ file ->getPath (), 'r ' );
645+ if (!$ sourceStream ) {
646+ throw new \Exception ("Failed to open source file {$ file ->getPath ()} ( {$ file ->getId ()}) " );
647+ }
648+ $ this ->objectStore ->writeObject ($ this ->getURN ($ file ->getId ()), $ sourceStream , $ file ->getMimeType ());
649+ if (is_resource ($ sourceStream )) {
650+ fclose ($ sourceStream );
651+ }
652+ $ copiedFiles [] = $ file ->getId ();
653+ }
654+ } catch (\Exception $ e ) {
655+ foreach ($ copiedFiles as $ fileId ) {
656+ try {
657+ $ this ->objectStore ->deleteObject ($ this ->getURN ($ fileId ));
658+ } catch (\Exception $ e ) {
659+ // ignore
660+ }
661+ }
662+ throw $ e ;
663+ }
664+ }
665+
666+ /**
667+ * @return \Iterator<ICacheEntry>
668+ */
669+ private function getAllChildObjects (ICache $ cache , ICacheEntry $ entry ): \Iterator {
670+ if ($ entry ->getMimeType () === FileInfo::MIMETYPE_FOLDER ) {
671+ foreach ($ cache ->getFolderContentsById ($ entry ->getId ()) as $ child ) {
672+ yield from $ this ->getAllChildObjects ($ cache , $ child );
673+ }
674+ } else {
675+ yield $ entry ;
676+ }
677+ }
678+
637679 public function copy ($ source , $ target ) {
638680 $ source = $ this ->normalizePath ($ source );
639681 $ target = $ this ->normalizePath ($ target );
0 commit comments