@@ -22,9 +22,12 @@ use crate::cmp;
22
22
use crate :: io:: { self , BorrowedCursor , IoSlice , IoSliceMut , Read } ;
23
23
use crate :: os:: unix:: io:: { AsFd , AsRawFd , BorrowedFd , FromRawFd , IntoRawFd , OwnedFd , RawFd } ;
24
24
use crate :: sys:: cvt;
25
- #[ cfg( all( target_os = "android" , target_pointer_width = "64" ) ) ]
25
+ #[ cfg( all( any ( target_os = "android" , target_os = "linux" ) , target_pointer_width = "64" ) ) ]
26
26
use crate :: sys:: pal:: weak:: syscall;
27
- #[ cfg( any( all( target_os = "android" , target_pointer_width = "32" ) , target_vendor = "apple" ) ) ]
27
+ #[ cfg( any(
28
+ all( any( target_os = "android" , target_os = "linux" ) , target_pointer_width = "32" ) ,
29
+ target_vendor = "apple"
30
+ ) ) ]
28
31
use crate :: sys:: pal:: weak:: weak;
29
32
use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
30
33
@@ -384,6 +387,16 @@ impl FileDesc {
384
387
) ) ]
385
388
use libc:: pwrite64;
386
389
390
+ // Work around linux deviating from POSIX where it ignores the
391
+ // offset of pwrite when the file was opened with O_APPEND.
392
+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
393
+ {
394
+ let iov = [ IoSlice :: new ( buf) ] ;
395
+ if let Some ( ret) = self . pwritev2 ( & iov, offset) {
396
+ return ret;
397
+ }
398
+ }
399
+
387
400
unsafe {
388
401
cvt ( pwrite64 (
389
402
self . as_raw_fd ( ) ,
@@ -408,6 +421,13 @@ impl FileDesc {
408
421
target_os = "openbsd" , // OpenBSD 2.7
409
422
) ) ]
410
423
pub fn write_vectored_at ( & self , bufs : & [ IoSlice < ' _ > ] , offset : u64 ) -> io:: Result < usize > {
424
+ // Work around linux deviating from POSIX where it ignores the
425
+ // offset of pwrite when the file was opened with O_APPEND.
426
+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
427
+ if let Some ( ret) = self . pwritev2 ( bufs, offset) {
428
+ return ret;
429
+ }
430
+
411
431
let ret = cvt ( unsafe {
412
432
libc:: pwritev (
413
433
self . as_raw_fd ( ) ,
@@ -611,6 +631,64 @@ impl FileDesc {
611
631
pub fn duplicate ( & self ) -> io:: Result < FileDesc > {
612
632
Ok ( Self ( self . 0 . try_clone ( ) ?) )
613
633
}
634
+
635
+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
636
+ fn pwritev2 ( & self , bufs : & [ IoSlice < ' _ > ] , offset : u64 ) -> Option < io:: Result < usize > > {
637
+ #[ cfg( target_pointer_width = "64" ) ]
638
+ syscall ! (
639
+ fn pwritev2(
640
+ fd: libc:: c_int,
641
+ iovec: * const libc:: iovec,
642
+ n_iovec: libc:: c_int,
643
+ offset: off64_t,
644
+ flags: libc:: c_int,
645
+ ) -> isize ;
646
+ ) ;
647
+ #[ cfg( target_pointer_width = "32" ) ]
648
+ let pwritev2 = {
649
+ weak ! (
650
+ fn pwritev2(
651
+ fd: libc:: c_int,
652
+ iovec: * const libc:: iovec,
653
+ n_iovec: libc:: c_int,
654
+ offset: off64_t,
655
+ flags: libc:: c_int,
656
+ ) -> isize ;
657
+ ) ;
658
+ let Some ( pwritev2) = pwritev2. get ( ) else {
659
+ return None ;
660
+ } ;
661
+ pwritev2
662
+ } ;
663
+
664
+ use core:: sync:: atomic:: AtomicBool ;
665
+
666
+ static NOAPPEND_SUPPORTED : AtomicBool = AtomicBool :: new ( true ) ;
667
+ if NOAPPEND_SUPPORTED . load ( core:: sync:: atomic:: Ordering :: Relaxed ) {
668
+ let r = unsafe {
669
+ cvt ( pwritev2 (
670
+ self . as_raw_fd ( ) ,
671
+ bufs. as_ptr ( ) as * const libc:: iovec ,
672
+ cmp:: min ( bufs. len ( ) , max_iov ( ) ) as libc:: c_int ,
673
+ offset as off64_t ,
674
+ libc:: RWF_NOAPPEND ,
675
+ ) )
676
+ } ;
677
+ match r {
678
+ Ok ( ret) => return Some ( Ok ( ret as usize ) ) ,
679
+ Err ( e)
680
+ if let Some ( err) = e. raw_os_error ( )
681
+ && ( err == libc:: EOPNOTSUPP || err == libc:: ENOSYS ) =>
682
+ {
683
+ NOAPPEND_SUPPORTED . store ( false , core:: sync:: atomic:: Ordering :: Relaxed ) ;
684
+ return None ;
685
+ }
686
+ Err ( e) => return Some ( Err ( e) ) ,
687
+ }
688
+ }
689
+
690
+ return None ;
691
+ }
614
692
}
615
693
616
694
impl < ' a > Read for & ' a FileDesc {
0 commit comments