@@ -3365,6 +3365,42 @@ def test_file2file_not_supported(self):
3365
3365
finally :
3366
3366
shutil ._USE_CP_SENDFILE = True
3367
3367
3368
+ def test_exception_on_enodata_call (self ):
3369
+ # Test logic when sendfile(2) call returns ENODATA error on
3370
+ # the not-first call on the file and we need to fall back to
3371
+ # traditional POSIX while preserving the position of where we
3372
+ # got to in writing
3373
+ def syscall (* args , ** kwargs ):
3374
+ if not flag :
3375
+ flag .append (None )
3376
+ return orig_syscall (* args , ** kwargs )
3377
+ else :
3378
+ raise OSError (errno .ENODATA , "yo" )
3379
+
3380
+ flag = []
3381
+ orig_syscall = eval (self .PATCHPOINT )
3382
+ # Reduce block size so that multiple syscalls are needed
3383
+ mock = unittest .mock .Mock ()
3384
+ mock .st_size = 65536 + 1
3385
+ with unittest .mock .patch ('os.fstat' , return_value = mock ) as m :
3386
+ with unittest .mock .patch (self .PATCHPOINT , create = True ,
3387
+ side_effect = syscall ) as m2 :
3388
+ with self .get_files () as (src , dst ):
3389
+ with self .assertRaises (_GiveupOnFastCopy ) as cm :
3390
+ self .zerocopy_fun (src , dst )
3391
+
3392
+ # Reset flag so that second syscall fails again
3393
+ flag = []
3394
+ with unittest .mock .patch (self .PATCHPOINT , create = True ,
3395
+ side_effect = syscall ) as m2 :
3396
+ shutil ._USE_CP_SENDFILE = True
3397
+ shutil .copyfile (TESTFN , TESTFN2 )
3398
+ assert m2 .called
3399
+ shutil ._USE_CP_SENDFILE = True
3400
+ assert flag
3401
+ self .assertEqual (read_file (TESTFN2 , binary = True ), self .FILEDATA )
3402
+
3403
+
3368
3404
3369
3405
@unittest .skipUnless (shutil ._USE_CP_COPY_FILE_RANGE , "os.copy_file_range() not supported" )
3370
3406
class TestZeroCopyCopyFileRange (_ZeroCopyFileLinuxTest , unittest .TestCase ):
0 commit comments