@@ -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,58 @@ 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
+ weak ! (
649
+ fn pwritev2(
650
+ fd: libc:: c_int,
651
+ iovec: * const libc:: iovec,
652
+ n_iovec: libc:: c_int,
653
+ offset: off64_t,
654
+ flags: libc:: c_int,
655
+ ) -> isize ;
656
+ ) ;
657
+
658
+ use core:: sync:: atomic:: AtomicBool ;
659
+
660
+ static NOAPPEND_SUPPORTED : AtomicBool = AtomicBool :: new ( true ) ;
661
+ if NOAPPEND_SUPPORTED . load ( core:: sync:: atomic:: Ordering :: Relaxed ) {
662
+ let r = unsafe {
663
+ cvt ( pwritev2 (
664
+ self . as_raw_fd ( ) ,
665
+ bufs. as_ptr ( ) as * const libc:: iovec ,
666
+ cmp:: min ( bufs. len ( ) , max_iov ( ) ) as libc:: c_int ,
667
+ offset as off64_t ,
668
+ libc:: RWF_NOAPPEND ,
669
+ ) )
670
+ } ;
671
+ match r {
672
+ Ok ( ret) => return Some ( Ok ( ret as usize ) ) ,
673
+ Err ( e)
674
+ if let Some ( err) = e. raw_os_error ( )
675
+ && ( err == libc:: EOPNOTSUPP || err == libc:: ENOSYS ) =>
676
+ {
677
+ NOAPPEND_SUPPORTED . store ( false , core:: sync:: atomic:: Ordering :: Relaxed ) ;
678
+ return None ;
679
+ }
680
+ Err ( e) => return Some ( Err ( e) ) ,
681
+ }
682
+ }
683
+
684
+ return None ;
685
+ }
614
686
}
615
687
616
688
impl < ' a > Read for & ' a FileDesc {
0 commit comments