2121from contextlib import closing
2222from functools import partial , wraps
2323
24- from . import copy , errors , fsencode , iotools , tools , walk , wildcard , glob
24+ from . import copy , errors , fsencode , glob , iotools , tools , walk , wildcard
2525from .copy import copy_modified_time
2626from .glob import BoundGlobber
2727from .mode import validate_open_mode
28- from .path import abspath , join , normpath
28+ from .path import abspath , isbase , join , normpath
2929from .time import datetime_to_epoch
3030from .walk import Walker
3131
@@ -423,13 +423,17 @@ def copy(
423423
424424 """
425425 with self ._lock :
426- if not overwrite and self .exists (dst_path ):
426+ _src_path = self .validatepath (src_path )
427+ _dst_path = self .validatepath (dst_path )
428+ if not overwrite and self .exists (_dst_path ):
427429 raise errors .DestinationExists (dst_path )
428- with closing (self .open (src_path , "rb" )) as read_file :
430+ if _src_path == _dst_path :
431+ raise errors .IllegalDestination (dst_path )
432+ with closing (self .open (_src_path , "rb" )) as read_file :
429433 # FIXME(@althonos): typing complains because open return IO
430- self .upload (dst_path , read_file ) # type: ignore
434+ self .upload (_dst_path , read_file ) # type: ignore
431435 if preserve_time :
432- copy_modified_time (self , src_path , self , dst_path )
436+ copy_modified_time (self , _src_path , self , _dst_path )
433437
434438 def copydir (
435439 self ,
@@ -457,11 +461,15 @@ def copydir(
457461
458462 """
459463 with self ._lock :
460- if not create and not self .exists (dst_path ):
464+ _src_path = self .validatepath (src_path )
465+ _dst_path = self .validatepath (dst_path )
466+ if isbase (_src_path , _dst_path ):
467+ raise errors .IllegalDestination (dst_path )
468+ if not create and not self .exists (_dst_path ):
461469 raise errors .ResourceNotFound (dst_path )
462- if not self .getinfo (src_path ).is_dir :
470+ if not self .getinfo (_src_path ).is_dir :
463471 raise errors .DirectoryExpected (src_path )
464- copy .copy_dir (self , src_path , self , dst_path , preserve_time = preserve_time )
472+ copy .copy_dir (self , _src_path , self , _dst_path , preserve_time = preserve_time )
465473
466474 def create (self , path , wipe = False ):
467475 # type: (Text, bool) -> bool
@@ -1088,6 +1096,12 @@ def movedir(self, src_path, dst_path, create=False, preserve_time=False):
10881096 from .move import move_dir
10891097
10901098 with self ._lock :
1099+ _src_path = self .validatepath (src_path )
1100+ _dst_path = self .validatepath (dst_path )
1101+ if _src_path == _dst_path :
1102+ return
1103+ if isbase (_src_path , _dst_path ):
1104+ raise errors .IllegalDestination (dst_path )
10911105 if not create and not self .exists (dst_path ):
10921106 raise errors .ResourceNotFound (dst_path )
10931107 move_dir (self , src_path , self , dst_path , preserve_time = preserve_time )
@@ -1157,14 +1171,19 @@ def move(self, src_path, dst_path, overwrite=False, preserve_time=False):
11571171 ``dst_path`` does not exist.
11581172
11591173 """
1160- if not overwrite and self .exists (dst_path ):
1174+ _src_path = self .validatepath (src_path )
1175+ _dst_path = self .validatepath (dst_path )
1176+ if not overwrite and self .exists (_dst_path ):
11611177 raise errors .DestinationExists (dst_path )
1162- if self .getinfo (src_path ).is_dir :
1178+ if self .getinfo (_src_path ).is_dir :
11631179 raise errors .FileExpected (src_path )
1180+ if _src_path == _dst_path :
1181+ # early exit when moving a file onto itself
1182+ return
11641183 if self .getmeta ().get ("supports_rename" , False ):
11651184 try :
1166- src_sys_path = self .getsyspath (src_path )
1167- dst_sys_path = self .getsyspath (dst_path )
1185+ src_sys_path = self .getsyspath (_src_path )
1186+ dst_sys_path = self .getsyspath (_dst_path )
11681187 except errors .NoSysPath : # pragma: no cover
11691188 pass
11701189 else :
@@ -1174,15 +1193,15 @@ def move(self, src_path, dst_path, overwrite=False, preserve_time=False):
11741193 pass
11751194 else :
11761195 if preserve_time :
1177- copy_modified_time (self , src_path , self , dst_path )
1196+ copy_modified_time (self , _src_path , self , _dst_path )
11781197 return
11791198 with self ._lock :
1180- with self .open (src_path , "rb" ) as read_file :
1199+ with self .open (_src_path , "rb" ) as read_file :
11811200 # FIXME(@althonos): typing complains because open return IO
1182- self .upload (dst_path , read_file ) # type: ignore
1201+ self .upload (_dst_path , read_file ) # type: ignore
11831202 if preserve_time :
1184- copy_modified_time (self , src_path , self , dst_path )
1185- self .remove (src_path )
1203+ copy_modified_time (self , _src_path , self , _dst_path )
1204+ self .remove (_src_path )
11861205
11871206 def open (
11881207 self ,
0 commit comments