@@ -601,32 +601,68 @@ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $t
601601 if (!$ sourceCacheEntry ) {
602602 $ sourceCacheEntry = $ sourceCache ->get ($ sourceInternalPath );
603603 }
604- if ($ sourceCacheEntry ->getMimeType () === FileInfo::MIMETYPE_FOLDER ) {
605- $ this ->mkdir ($ targetInternalPath );
606- foreach ($ sourceCache ->getFolderContentsById ($ sourceCacheEntry ->getId ()) as $ child ) {
607- $ this ->moveFromStorage ($ sourceStorage , $ child ->getPath (), $ targetInternalPath . '/ ' . $ child ->getName (), $ child );
608- }
604+
605+ $ this ->copyObjects ($ sourceStorage , $ sourceCache , $ sourceCacheEntry );
606+ if ($ sourceStorage ->instanceOfStorage (ObjectStoreStorage::class)) {
607+ /** @var ObjectStoreStorage $sourceStorage */
608+ $ sourceStorage ->setPreserveCacheOnDelete (true );
609+ }
610+ if ($ sourceCacheEntry ->getMimeType () === ICacheEntry::DIRECTORY_MIMETYPE ) {
609611 $ sourceStorage ->rmdir ($ sourceInternalPath );
610- $ sourceStorage ->getCache ()->remove ($ sourceInternalPath );
611612 } else {
612- $ sourceStream = $ sourceStorage ->fopen ($ sourceInternalPath , 'r ' );
613- if (!$ sourceStream ) {
614- return false ;
615- }
616- // move the cache entry before the contents so that we have the correct fileid/urn for the target
617- $ this ->getCache ()->moveFromCache ($ sourceCache , $ sourceInternalPath , $ targetInternalPath );
618- try {
619- $ this ->writeStream ($ targetInternalPath , $ sourceStream , $ sourceCacheEntry ->getSize ());
620- } catch (\Exception $ e ) {
621- // restore the cache entry
622- $ sourceCache ->moveFromCache ($ this ->getCache (), $ targetInternalPath , $ sourceInternalPath );
623- throw $ e ;
624- }
625613 $ sourceStorage ->unlink ($ sourceInternalPath );
626614 }
615+ if ($ sourceStorage ->instanceOfStorage (ObjectStoreStorage::class)) {
616+ /** @var ObjectStoreStorage $sourceStorage */
617+ $ sourceStorage ->setPreserveCacheOnDelete (false );
618+ }
619+ $ this ->getCache ()->moveFromCache ($ sourceCache , $ sourceInternalPath , $ targetInternalPath );
620+
627621 return true ;
628622 }
629623
624+ /**
625+ * Copy the object(s) of a file or folder into this storage, without touching the cache
626+ */
627+ private function copyObjects (IStorage $ sourceStorage , ICache $ sourceCache , ICacheEntry $ sourceCacheEntry ) {
628+ $ copiedFiles = [];
629+ try {
630+ foreach ($ this ->getAllChildObjects ($ sourceCache , $ sourceCacheEntry ) as $ file ) {
631+ $ sourceStream = $ sourceStorage ->fopen ($ file ->getPath (), 'r ' );
632+ if (!$ sourceStream ) {
633+ throw new \Exception ("Failed to open source file {$ file ->getPath ()} ( {$ file ->getId ()}) " );
634+ }
635+ $ this ->objectStore ->writeObject ($ this ->getURN ($ file ->getId ()), $ sourceStream , $ file ->getMimeType ());
636+ if (is_resource ($ sourceStream )) {
637+ fclose ($ sourceStream );
638+ }
639+ $ copiedFiles [] = $ file ->getId ();
640+ }
641+ } catch (\Exception $ e ) {
642+ foreach ($ copiedFiles as $ fileId ) {
643+ try {
644+ $ this ->objectStore ->deleteObject ($ this ->getURN ($ fileId ));
645+ } catch (\Exception $ e ) {
646+ // ignore
647+ }
648+ }
649+ throw $ e ;
650+ }
651+ }
652+
653+ /**
654+ * @return \Iterator<ICacheEntry>
655+ */
656+ private function getAllChildObjects (ICache $ cache , ICacheEntry $ entry ): \Iterator {
657+ if ($ entry ->getMimeType () === FileInfo::MIMETYPE_FOLDER ) {
658+ foreach ($ cache ->getFolderContentsById ($ entry ->getId ()) as $ child ) {
659+ yield from $ this ->getAllChildObjects ($ cache , $ child );
660+ }
661+ } else {
662+ yield $ entry ;
663+ }
664+ }
665+
630666 public function copy ($ source , $ target ): bool {
631667 $ source = $ this ->normalizePath ($ source );
632668 $ target = $ this ->normalizePath ($ target );
0 commit comments