@@ -843,7 +843,7 @@ mod preadv2 {
843
843
844
844
#[ test]
845
845
fn test_preadv2_safe ( ) {
846
- use std:: io:: Write ;
846
+ use std:: io:: { Seek , Write } ;
847
847
use std:: mem:: MaybeUninit ;
848
848
use tempfile:: tempdir;
849
849
@@ -883,6 +883,19 @@ mod preadv2 {
883
883
br. clear ( ) ;
884
884
preadv2_safe ( & f, & mut br, -1 , 0 ) . unwrap ( ) ;
885
885
assert_eq ! ( br. filled( ) , b" test" ) ;
886
+
887
+ // Test handling large offsets
888
+ {
889
+ // I hope the underlying filesystem supports sparse files
890
+ let mut w = std:: fs:: OpenOptions :: new ( ) . write ( true ) . open ( & filename) . unwrap ( ) ;
891
+ w. set_len ( 0x1_0000_0000 ) . unwrap ( ) ;
892
+ w. seek ( std:: io:: SeekFrom :: Start ( 0x1_0000_0000 ) ) . unwrap ( ) ;
893
+ w. write ( b"This is a Large File" ) . unwrap ( ) ;
894
+ }
895
+
896
+ br. clear ( ) ;
897
+ preadv2_safe ( & f, & mut br, 0x1_0000_0008 , 0 ) . unwrap ( ) ;
898
+ assert_eq ! ( br. filled( ) , b"a Large File" ) ;
886
899
}
887
900
}
888
901
@@ -900,14 +913,18 @@ mod preadv2 {
900
913
)
901
914
}
902
915
903
- const RWF_NOWAIT : c_int = 0x00000008 ;
916
+ pub ( crate ) const RWF_NOWAIT : c_int = 0x00000008 ;
904
917
unsafe fn preadv2 (
905
918
fd : c_int ,
906
919
iov : * const iovec ,
907
920
iovcnt : c_int ,
908
921
offset : off_t ,
909
922
flags : c_int ,
910
923
) -> ssize_t {
924
+ // Call via libc::syscall rather than libc::preadv2. preadv2 is only supported by glibc
925
+ // and only since v2.26. By using syscall we don't need to worry about compatiblity with
926
+ // old glibc versions and it will work on Android and musl too. The downside is that you
927
+ // can't use `LD_PRELOAD` tricks any more to intercept these calls.
911
928
let ( lo, hi) = pos_to_lohi ( offset) ;
912
929
libc:: syscall ( libc:: SYS_preadv2 , fd, iov, iovcnt, lo, hi, flags) as ssize_t
913
930
}
0 commit comments