6363use OCP \Files \InvalidCharacterInPathException ;
6464use OCP \Files \InvalidDirectoryException ;
6565use OCP \Files \InvalidPathException ;
66+ use OCP \Files \Mount \IMountManager ;
6667use OCP \Files \Mount \IMountPoint ;
6768use OCP \Files \NotFoundException ;
6869use OCP \Files \ReservedWordException ;
6970use OCP \Files \Storage \IStorage ;
71+ use OCP \IL10N ;
7072use OCP \IUser ;
73+ use OCP \L10N \IFactory ;
7174use OCP \Lock \ILockingProvider ;
7275use OCP \Lock \LockedException ;
7376use Psr \Log \LoggerInterface ;
@@ -95,6 +98,7 @@ class View {
9598 private bool $ updaterEnabled = true ;
9699 private UserManager $ userManager ;
97100 private LoggerInterface $ logger ;
101+ private IL10N $ l10n ;
98102
99103 /**
100104 * @throws \Exception If $root contains an invalid path
@@ -109,6 +113,7 @@ public function __construct(string $root = '') {
109113 $ this ->lockingEnabled = !($ this ->lockingProvider instanceof \OC \Lock \NoopLockingProvider);
110114 $ this ->userManager = \OC ::$ server ->getUserManager ();
111115 $ this ->logger = \OC ::$ server ->get (LoggerInterface::class);
116+ $ this ->l10n = \OC ::$ server ->get (IFactory::class)->get ('files ' );
112117 }
113118
114119 /**
@@ -725,18 +730,26 @@ public function deleteAll($directory) {
725730 *
726731 * @param string $source source path
727732 * @param string $target target path
733+ * @param array $options
728734 *
729735 * @return bool|mixed
730736 * @throws LockedException
731737 */
732- public function rename ($ source , $ target ) {
738+ public function rename ($ source , $ target , array $ options = []) {
739+ $ checkSubMounts = $ options ['checkSubMounts ' ] ?? true ;
740+
733741 $ absolutePath1 = Filesystem::normalizePath ($ this ->getAbsolutePath ($ source ));
734742 $ absolutePath2 = Filesystem::normalizePath ($ this ->getAbsolutePath ($ target ));
735743
736744 if (str_starts_with ($ absolutePath2 , $ absolutePath1 . '/ ' )) {
737745 throw new ForbiddenException ("Moving a folder into a child folder is forbidden " , false );
738746 }
739747
748+ /** @var IMountManager $mountManager */
749+ $ mountManager = \OC ::$ server ->get (IMountManager::class);
750+
751+ $ targetParts = explode ('/ ' , $ absolutePath2 );
752+ $ targetUser = $ targetParts [1 ] ?? null ;
740753 $ result = false ;
741754 if (
742755 Filesystem::isValidPath ($ target )
@@ -788,31 +801,38 @@ public function rename($source, $target) {
788801 try {
789802 $ this ->changeLock ($ target , ILockingProvider::LOCK_EXCLUSIVE , true );
790803
804+ if ($ checkSubMounts ) {
805+ $ movedMounts = $ mountManager ->findIn ($ this ->getAbsolutePath ($ source ));
806+ } else {
807+ $ movedMounts = [];
808+ }
809+
791810 if ($ internalPath1 === '' ) {
792- if ($ mount1 instanceof MoveableMount) {
793- $ sourceParentMount = $ this ->getMount (dirname ($ source ));
794- if ($ sourceParentMount === $ mount2 && $ this ->targetIsNotShared ($ storage2 , $ internalPath2 )) {
795- /**
796- * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
797- */
798- $ sourceMountPoint = $ mount1 ->getMountPoint ();
799- $ result = $ mount1 ->moveMount ($ absolutePath2 );
800- $ manager ->moveMount ($ sourceMountPoint , $ mount1 ->getMountPoint ());
801- } else {
802- $ result = false ;
803- }
804- } else {
805- $ result = false ;
806- }
811+ $ sourceParentMount = $ this ->getMount (dirname ($ source ));
812+ $ movedMounts [] = $ mount1 ;
813+ $ this ->validateMountMove ($ movedMounts , $ sourceParentMount , $ mount2 , !$ this ->targetIsNotShared ($ storage2 , $ internalPath2 ));
814+ /**
815+ * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
816+ */
817+ $ sourceMountPoint = $ mount1 ->getMountPoint ();
818+ $ result = $ mount1 ->moveMount ($ absolutePath2 );
819+ $ manager ->moveMount ($ sourceMountPoint , $ mount1 ->getMountPoint ());
820+
807821 // moving a file/folder within the same mount point
808822 } elseif ($ storage1 === $ storage2 ) {
823+ if (count ($ movedMounts ) > 0 ) {
824+ $ this ->validateMountMove ($ movedMounts , $ mount1 , $ mount2 , !$ this ->targetIsNotShared ($ storage2 , $ absolutePath2 ));
825+ }
809826 if ($ storage1 ) {
810827 $ result = $ storage1 ->rename ($ internalPath1 , $ internalPath2 );
811828 } else {
812829 $ result = false ;
813830 }
814831 // moving a file/folder between storages (from $storage1 to $storage2)
815832 } else {
833+ if (count ($ movedMounts ) > 0 ) {
834+ $ this ->validateMountMove ($ movedMounts , $ mount1 , $ mount2 , !$ this ->targetIsNotShared ($ storage2 , $ absolutePath2 ));
835+ }
816836 $ result = $ storage2 ->moveFromStorage ($ storage1 , $ internalPath1 , $ internalPath2 );
817837 }
818838
@@ -862,6 +882,55 @@ public function rename($source, $target) {
862882 return $ result ;
863883 }
864884
885+ /**
886+ * @throws ForbiddenException
887+ */
888+ private function validateMountMove (array $ mounts , IMountPoint $ sourceMount , IMountPoint $ targetMount , bool $ targetIsShared ): void {
889+ $ targetPath = $ this ->getRelativePath ($ targetMount ->getMountPoint ());
890+ if ($ targetPath ) {
891+ $ targetPath = trim ($ targetPath , '/ ' );
892+ } else {
893+ $ targetPath = $ targetMount ->getMountPoint ();
894+ }
895+
896+ foreach ($ mounts as $ mount ) {
897+ $ sourcePath = $ this ->getRelativePath ($ mount ->getMountPoint ());
898+ if ($ sourcePath ) {
899+ $ sourcePath = trim ($ sourcePath , '/ ' );
900+ } else {
901+ $ sourcePath = $ mount ->getMountPoint ();
902+ }
903+
904+ if (!$ mount instanceof MoveableMount) {
905+ throw new ForbiddenException ($ this ->l10n ->t ('Storage %s cannot be moved ' , [$ sourcePath ]), false );
906+ }
907+
908+ if ($ targetIsShared ) {
909+ if ($ sourceMount instanceof SharedMount) {
910+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a share (%s) into a shared folder is not allowed ' , [$ sourcePath ]), false );
911+ } else {
912+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a storage (%s) into a shared folder is not allowed ' , [$ sourcePath ]), false );
913+ }
914+ }
915+
916+ if ($ sourceMount !== $ targetMount ) {
917+ if ($ sourceMount instanceof SharedMount) {
918+ if ($ targetMount instanceof SharedMount) {
919+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a share (%s) into another share (%s) is not allowed ' , [$ sourcePath , $ targetPath ]), false );
920+ } else {
921+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a share (%s) into another storage (%s) is not allowed ' , [$ sourcePath , $ targetPath ]), false );
922+ }
923+ } else {
924+ if ($ targetMount instanceof SharedMount) {
925+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a storage (%s) into a share (%s) is not allowed ' , [$ sourcePath , $ targetPath ]), false );
926+ } else {
927+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a storage (%s) into another storage (%s) is not allowed ' , [$ sourcePath , $ targetPath ]), false );
928+ }
929+ }
930+ }
931+ }
932+ }
933+
865934 /**
866935 * Copy a file/folder from the source path to target path
867936 *
0 commit comments