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 ;
70+ use OCP \IL10N ;
6971use OCP \IUser ;
72+ use OCP \L10N \IFactory ;
7073use OCP \Lock \ILockingProvider ;
7174use OCP \Lock \LockedException ;
7275use OCP \Server ;
@@ -97,6 +100,7 @@ class View {
97100 private bool $ updaterEnabled = true ;
98101 private UserManager $ userManager ;
99102 private LoggerInterface $ logger ;
103+ private IL10N $ l10n ;
100104
101105 /**
102106 * @throws \Exception If $root contains an invalid path
@@ -111,6 +115,7 @@ public function __construct(string $root = '') {
111115 $ this ->lockingEnabled = !($ this ->lockingProvider instanceof \OC \Lock \NoopLockingProvider);
112116 $ this ->userManager = \OC ::$ server ->getUserManager ();
113117 $ this ->logger = \OC ::$ server ->get (LoggerInterface::class);
118+ $ this ->l10n = \OC ::$ server ->get (IFactory::class)->get ('files ' );
114119 }
115120
116121 /**
@@ -727,18 +732,24 @@ public function deleteAll($directory) {
727732 *
728733 * @param string $source source path
729734 * @param string $target target path
735+ * @param array $options
730736 *
731737 * @return bool|mixed
732738 * @throws LockedException
733739 */
734- public function rename ($ source , $ target ) {
740+ public function rename ($ source , $ target , array $ options = []) {
741+ $ checkSubMounts = $ options ['checkSubMounts ' ] ?? true ;
742+
735743 $ absolutePath1 = Filesystem::normalizePath ($ this ->getAbsolutePath ($ source ));
736744 $ absolutePath2 = Filesystem::normalizePath ($ this ->getAbsolutePath ($ target ));
737745
738746 if (str_starts_with ($ absolutePath2 , $ absolutePath1 . '/ ' )) {
739747 throw new ForbiddenException ("Moving a folder into a child folder is forbidden " , false );
740748 }
741749
750+ /** @var IMountManager $mountManager */
751+ $ mountManager = \OC ::$ server ->get (IMountManager::class);
752+
742753 $ targetParts = explode ('/ ' , $ absolutePath2 );
743754 $ targetUser = $ targetParts [1 ] ?? null ;
744755 $ result = false ;
@@ -792,31 +803,38 @@ public function rename($source, $target) {
792803 try {
793804 $ this ->changeLock ($ target , ILockingProvider::LOCK_EXCLUSIVE , true );
794805
806+ if ($ checkSubMounts ) {
807+ $ movedMounts = $ mountManager ->findIn ($ this ->getAbsolutePath ($ source ));
808+ } else {
809+ $ movedMounts = [];
810+ }
811+
795812 if ($ internalPath1 === '' ) {
796- if ($ mount1 instanceof MoveableMount) {
797- $ sourceParentMount = $ this ->getMount (dirname ($ source ));
798- if ($ sourceParentMount === $ mount2 && $ this ->targetIsNotShared ($ targetUser , $ absolutePath2 )) {
799- /**
800- * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
801- */
802- $ sourceMountPoint = $ mount1 ->getMountPoint ();
803- $ result = $ mount1 ->moveMount ($ absolutePath2 );
804- $ manager ->moveMount ($ sourceMountPoint , $ mount1 ->getMountPoint ());
805- } else {
806- $ result = false ;
807- }
808- } else {
809- $ result = false ;
810- }
813+ $ sourceParentMount = $ this ->getMount (dirname ($ source ));
814+ $ movedMounts [] = $ mount1 ;
815+ $ this ->validateMountMove ($ movedMounts , $ sourceParentMount , $ mount2 , !$ this ->targetIsNotShared ($ targetUser , $ absolutePath2 ));
816+ /**
817+ * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
818+ */
819+ $ sourceMountPoint = $ mount1 ->getMountPoint ();
820+ $ result = $ mount1 ->moveMount ($ absolutePath2 );
821+ $ manager ->moveMount ($ sourceMountPoint , $ mount1 ->getMountPoint ());
822+
811823 // moving a file/folder within the same mount point
812824 } elseif ($ storage1 === $ storage2 ) {
825+ if (count ($ movedMounts ) > 0 ) {
826+ $ this ->validateMountMove ($ movedMounts , $ mount1 , $ mount2 , !$ this ->targetIsNotShared ($ targetUser , $ absolutePath2 ));
827+ }
813828 if ($ storage1 ) {
814829 $ result = $ storage1 ->rename ($ internalPath1 , $ internalPath2 );
815830 } else {
816831 $ result = false ;
817832 }
818833 // moving a file/folder between storages (from $storage1 to $storage2)
819834 } else {
835+ if (count ($ movedMounts ) > 0 ) {
836+ $ this ->validateMountMove ($ movedMounts , $ mount1 , $ mount2 , !$ this ->targetIsNotShared ($ targetUser , $ absolutePath2 ));
837+ }
820838 $ result = $ storage2 ->moveFromStorage ($ storage1 , $ internalPath1 , $ internalPath2 );
821839 }
822840
@@ -866,6 +884,55 @@ public function rename($source, $target) {
866884 return $ result ;
867885 }
868886
887+ /**
888+ * @throws ForbiddenException
889+ */
890+ private function validateMountMove (array $ mounts , IMountPoint $ sourceMount , IMountPoint $ targetMount , bool $ targetIsShared ): void {
891+ $ targetPath = $ this ->getRelativePath ($ targetMount ->getMountPoint ());
892+ if ($ targetPath ) {
893+ $ targetPath = trim ($ targetPath , '/ ' );
894+ } else {
895+ $ targetPath = $ targetMount ->getMountPoint ();
896+ }
897+
898+ foreach ($ mounts as $ mount ) {
899+ $ sourcePath = $ this ->getRelativePath ($ mount ->getMountPoint ());
900+ if ($ sourcePath ) {
901+ $ sourcePath = trim ($ sourcePath , '/ ' );
902+ } else {
903+ $ sourcePath = $ mount ->getMountPoint ();
904+ }
905+
906+ if (!$ mount instanceof MoveableMount) {
907+ throw new ForbiddenException ($ this ->l10n ->t ('Storage %s cannot be moved ' , [$ sourcePath ]), false );
908+ }
909+
910+ if ($ targetIsShared ) {
911+ if ($ sourceMount instanceof SharedMount) {
912+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a share (%s) into a shared folder is not allowed ' , [$ sourcePath ]), false );
913+ } else {
914+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a storage (%s) into a shared folder is not allowed ' , [$ sourcePath ]), false );
915+ }
916+ }
917+
918+ if ($ sourceMount !== $ targetMount ) {
919+ if ($ sourceMount instanceof SharedMount) {
920+ if ($ targetMount instanceof SharedMount) {
921+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a share (%s) into another share (%s) is not allowed ' , [$ sourcePath , $ targetPath ]), false );
922+ } else {
923+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a share (%s) into another storage (%s) is not allowed ' , [$ sourcePath , $ targetPath ]), false );
924+ }
925+ } else {
926+ if ($ targetMount instanceof SharedMount) {
927+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a storage (%s) into a share (%s) is not allowed ' , [$ sourcePath , $ targetPath ]), false );
928+ } else {
929+ throw new ForbiddenException ($ this ->l10n ->t ('Moving a storage (%s) into another storage (%s) is not allowed ' , [$ sourcePath , $ targetPath ]), false );
930+ }
931+ }
932+ }
933+ }
934+ }
935+
869936 /**
870937 * Copy a file/folder from the source path to target path
871938 *
0 commit comments