11
11
resemble pathlib's PurePath and Path respectively.
12
12
"""
13
13
14
+ import errno
14
15
import functools
15
16
import operator
16
17
import posixpath
@@ -564,14 +565,33 @@ def samefile(self, other_path):
564
565
return (st .st_ino == other_st .st_ino and
565
566
st .st_dev == other_st .st_dev )
566
567
567
- def _samefile_safe (self , other_path ):
568
+ def _ensure_different_file (self , other_path ):
568
569
"""
569
- Like samefile(), but returns False rather than raising OSError .
570
+ Raise OSError(EINVAL) if both paths refer to the same file .
570
571
"""
571
572
try :
572
- return self .samefile (other_path )
573
+ if not self .samefile (other_path ):
574
+ return
573
575
except (OSError , ValueError ):
574
- return False
576
+ return
577
+ err = OSError (errno .EINVAL , "Source and target are the same file" )
578
+ err .filename = str (self )
579
+ err .filename2 = str (other_path )
580
+ raise err
581
+
582
+ def _ensure_distinct_path (self , other_path ):
583
+ """
584
+ Raise OSError(EINVAL) if the other path is within this path.
585
+ """
586
+ if self == other_path :
587
+ err = OSError (errno .EINVAL , "Source and target are the same path" )
588
+ elif self in other_path .parents :
589
+ err = OSError (errno .EINVAL , "Source path is a parent of target path" )
590
+ else :
591
+ return
592
+ err .filename = str (self )
593
+ err .filename2 = str (other_path )
594
+ raise err
575
595
576
596
def open (self , mode = 'r' , buffering = - 1 , encoding = None ,
577
597
errors = None , newline = None ):
@@ -826,8 +846,7 @@ def _copy_file(self, target):
826
846
"""
827
847
Copy the contents of this file to the given target.
828
848
"""
829
- if self ._samefile_safe (target ):
830
- raise OSError (f"{ self !r} and { target !r} are the same file" )
849
+ self ._ensure_different_file (target )
831
850
with self .open ('rb' ) as source_f :
832
851
try :
833
852
with target .open ('wb' ) as target_f :
@@ -847,6 +866,13 @@ def copy(self, target, *, follow_symlinks=True, dirs_exist_ok=False,
847
866
"""
848
867
if not isinstance (target , PathBase ):
849
868
target = self .with_segments (target )
869
+ try :
870
+ self ._ensure_distinct_path (target )
871
+ except OSError as err :
872
+ if on_error is None :
873
+ raise
874
+ on_error (err )
875
+ return
850
876
stack = [(self , target )]
851
877
while stack :
852
878
src , dst = stack .pop ()
0 commit comments