@@ -7,11 +7,7 @@ use {crate::syscall_u32, std::os::unix::prelude::AsRawFd};
7
7
#[ cfg( all( windows, any( feature = "legacy" , feature = "poll-io" ) ) ) ]
8
8
use {
9
9
std:: ffi:: c_void,
10
- windows_sys:: Win32 :: {
11
- Foundation :: TRUE ,
12
- Networking :: WinSock :: { WSAGetLastError , WSARecv , WSAESHUTDOWN } ,
13
- Storage :: FileSystem :: { ReadFile , SetFilePointer , FILE_BEGIN , INVALID_SET_FILE_POINTER } ,
14
- } ,
10
+ windows_sys:: Win32 :: { Foundation :: TRUE , Storage :: FileSystem :: ReadFile } ,
15
11
} ;
16
12
17
13
use super :: { super :: shared_fd:: SharedFd , Op , OpAble } ;
@@ -42,7 +38,18 @@ impl<T: IoBufMut> Op<Read<T>> {
42
38
} )
43
39
}
44
40
45
- pub ( crate ) async fn read ( self ) -> BufResult < usize , T > {
41
+ pub ( crate ) fn read ( fd : SharedFd , buf : T ) -> io:: Result < Op < Read < T > > > {
42
+ Op :: submit_with ( Read {
43
+ fd,
44
+ buf,
45
+ // Refers to https://docs.rs/io-uring/latest/io_uring/opcode/struct.Write.html.
46
+ // If `offset` is set to `-1`, the offset will use (and advance) the file position, like
47
+ // the read(2) and write(2) system calls.
48
+ offset : -1i64 as u64 ,
49
+ } )
50
+ }
51
+
52
+ pub ( crate ) async fn result ( self ) -> BufResult < usize , T > {
46
53
let complete = self . await ;
47
54
48
55
// Convert the operation result to `usize`
@@ -83,54 +90,69 @@ impl<T: IoBufMut> OpAble for Read<T> {
83
90
#[ cfg( all( any( feature = "legacy" , feature = "poll-io" ) , unix) ) ]
84
91
fn legacy_call ( & mut self ) -> io:: Result < u32 > {
85
92
let fd = self . fd . as_raw_fd ( ) ;
86
- let seek_offset = libc:: off_t:: try_from ( self . offset )
87
- . map_err ( |_| io:: Error :: new ( io:: ErrorKind :: Other , "offset too big" ) ) ?;
88
- #[ cfg( not( target_os = "macos" ) ) ]
89
- return syscall_u32 ! ( pread64(
90
- fd,
91
- self . buf. write_ptr( ) as _,
92
- self . buf. bytes_total( ) ,
93
- seek_offset as _
94
- ) ) ;
95
93
96
- #[ cfg( target_os = "macos" ) ]
97
- return syscall_u32 ! ( pread(
98
- fd,
99
- self . buf. write_ptr( ) as _,
100
- self . buf. bytes_total( ) ,
101
- seek_offset
102
- ) ) ;
94
+ let mut seek_offset = -1 ;
95
+
96
+ if -1i64 as u64 != self . offset {
97
+ seek_offset = libc:: off_t:: try_from ( self . offset )
98
+ . map_err ( |_| io:: Error :: new ( io:: ErrorKind :: Other , "offset too big" ) ) ?;
99
+ }
100
+
101
+ if seek_offset == -1 {
102
+ syscall_u32 ! ( read( fd, self . buf. write_ptr( ) as _, self . buf. bytes_total( ) ) )
103
+ } else {
104
+ syscall_u32 ! ( pread(
105
+ fd,
106
+ self . buf. write_ptr( ) as _,
107
+ self . buf. bytes_total( ) ,
108
+ seek_offset as _
109
+ ) )
110
+ }
103
111
}
104
112
105
113
#[ cfg( all( any( feature = "legacy" , feature = "poll-io" ) , windows) ) ]
106
114
fn legacy_call ( & mut self ) -> io:: Result < u32 > {
115
+ use windows_sys:: Win32 :: {
116
+ Foundation :: { GetLastError , ERROR_HANDLE_EOF } ,
117
+ System :: IO :: OVERLAPPED ,
118
+ } ;
119
+
107
120
let fd = self . fd . raw_handle ( ) as _ ;
108
- let seek_offset = libc :: off_t :: try_from ( self . offset )
109
- . map_err ( |_| io :: Error :: new ( io :: ErrorKind :: Other , "offset too big" ) ) ? ;
121
+ let seek_offset = self . offset ;
122
+
110
123
let mut bytes_read = 0 ;
111
124
let ret = unsafe {
112
- // see https://learn.microsoft.com/zh-cn/windows/win32/api/fileapi/nf-fileapi-setfilepointer
113
- if seek_offset != 0 {
114
- // We use `FILE_BEGIN` because this behavior should be the same with unix syscall
115
- // `pwrite`, which uses the offset from the begin of the file.
116
- let r = SetFilePointer ( fd, seek_offset, std:: ptr:: null_mut ( ) , FILE_BEGIN ) ;
117
- if INVALID_SET_FILE_POINTER == r {
118
- return Err ( io:: Error :: last_os_error ( ) ) ;
119
- }
120
- }
121
125
// see https://learn.microsoft.com/zh-cn/windows/win32/api/fileapi/nf-fileapi-readfile
122
- ReadFile (
123
- fd,
124
- self . buf . write_ptr ( ) . cast :: < c_void > ( ) ,
125
- self . buf . bytes_total ( ) as u32 ,
126
- & mut bytes_read,
127
- std:: ptr:: null_mut ( ) ,
128
- )
126
+ if seek_offset as i64 != -1 {
127
+ let mut overlapped: OVERLAPPED = std:: mem:: zeroed ( ) ;
128
+ overlapped. Anonymous . Anonymous . Offset = seek_offset as u32 ; // Lower 32 bits of the offset
129
+ overlapped. Anonymous . Anonymous . OffsetHigh = ( seek_offset >> 32 ) as u32 ; // Higher 32 bits of the offset
130
+
131
+ ReadFile (
132
+ fd,
133
+ self . buf . write_ptr ( ) . cast :: < c_void > ( ) ,
134
+ self . buf . bytes_total ( ) as u32 ,
135
+ & mut bytes_read,
136
+ & overlapped as * const _ as * mut _ ,
137
+ )
138
+ } else {
139
+ ReadFile (
140
+ fd,
141
+ self . buf . write_ptr ( ) . cast :: < c_void > ( ) ,
142
+ self . buf . bytes_total ( ) as u32 ,
143
+ & mut bytes_read,
144
+ std:: ptr:: null_mut ( ) ,
145
+ )
146
+ }
129
147
} ;
130
- if TRUE == ret {
131
- Ok ( bytes_read)
132
- } else {
133
- Err ( io:: Error :: last_os_error ( ) )
148
+
149
+ if ret == TRUE {
150
+ return Ok ( bytes_read) ;
151
+ }
152
+
153
+ match unsafe { GetLastError ( ) } {
154
+ ERROR_HANDLE_EOF => Ok ( bytes_read) ,
155
+ error => Err ( io:: Error :: from_raw_os_error ( error as _ ) ) ,
134
156
}
135
157
}
136
158
}
@@ -140,17 +162,25 @@ pub(crate) struct ReadVec<T> {
140
162
/// while the operation is in-flight.
141
163
#[ allow( unused) ]
142
164
fd : SharedFd ,
165
+ offset : u64 ,
143
166
144
167
/// Reference to the in-flight buffer.
145
168
pub ( crate ) buf_vec : T ,
146
169
}
147
170
148
171
impl < T : IoVecBufMut > Op < ReadVec < T > > {
149
172
pub ( crate ) fn readv ( fd : SharedFd , buf_vec : T ) -> io:: Result < Self > {
150
- Op :: submit_with ( ReadVec { fd, buf_vec } )
173
+ Op :: submit_with ( ReadVec {
174
+ fd,
175
+ // Refers to https://docs.rs/io-uring/latest/io_uring/opcode/struct.Write.html.
176
+ // If `offset` is set to `-1`, the offset will use (and advance) the file position, like
177
+ // the readv(2) system calls.
178
+ offset : -1i64 as u64 ,
179
+ buf_vec,
180
+ } )
151
181
}
152
182
153
- pub ( crate ) async fn read ( self ) -> BufResult < usize , T > {
183
+ pub ( crate ) async fn result ( self ) -> BufResult < usize , T > {
154
184
let complete = self . await ;
155
185
let res = complete. meta . result . map ( |v| v as _ ) ;
156
186
let mut buf_vec = complete. data . buf_vec ;
@@ -168,7 +198,9 @@ impl<T: IoVecBufMut> OpAble for ReadVec<T> {
168
198
fn uring_op ( & mut self ) -> io_uring:: squeue:: Entry {
169
199
let ptr = self . buf_vec . write_iovec_ptr ( ) as _ ;
170
200
let len = self . buf_vec . write_iovec_len ( ) as _ ;
171
- opcode:: Readv :: new ( types:: Fd ( self . fd . raw_fd ( ) ) , ptr, len) . build ( )
201
+ opcode:: Readv :: new ( types:: Fd ( self . fd . raw_fd ( ) ) , ptr, len)
202
+ . offset ( self . offset )
203
+ . build ( )
172
204
}
173
205
174
206
#[ cfg( any( feature = "legacy" , feature = "poll-io" ) ) ]
@@ -188,6 +220,11 @@ impl<T: IoVecBufMut> OpAble for ReadVec<T> {
188
220
189
221
#[ cfg( all( any( feature = "legacy" , feature = "poll-io" ) , windows) ) ]
190
222
fn legacy_call ( & mut self ) -> io:: Result < u32 > {
223
+ // There is no `readv` like syscall of file on windows, but this will be used to send
224
+ // socket message.
225
+
226
+ use windows_sys:: Win32 :: Networking :: WinSock :: { WSAGetLastError , WSARecv , WSAESHUTDOWN } ;
227
+
191
228
let mut nread = 0 ;
192
229
let mut flags = 0 ;
193
230
let ret = unsafe {
0 commit comments