1use crate::Metadata;
11use io_lifetimes::AsFilelike;
12use std::fs::File;
13use std::io::{self, IoSlice, IoSliceMut};
14use std::os::windows::fs::FileExt;
15use std::slice;
16#[cfg(feature = "io-streams")]
17use {
18 crate::owned_streamer::OwnedStreamer,
19 cap_fs_ext::{OpenOptions, Reopen},
20 io_streams::StreamReader,
21 std::io::SeekFrom,
22 system_interface::fs::FileIoExt,
23};
24
25#[inline]
27pub fn metadata<'a, Filelike: AsFilelike>(filelike: &Filelike) -> io::Result<Metadata> {
28 filelike.as_filelike_view::<File>().metadata().map(|meta| {
29 Metadata {
30 len: meta.len(),
31
32 blksize: 0x1000,
35 }
36 })
37}
38
39#[inline]
41pub fn read_at<'a, Filelike: AsFilelike>(
42 filelike: &Filelike,
43 buf: &mut [u8],
44 offset: u64,
45) -> io::Result<usize> {
46 filelike.as_filelike_view::<File>().seek_read(buf, offset)
47}
48
49pub fn read_exact_at<Filelike: AsFilelike>(
51 filelike: &Filelike,
52 mut buf: &mut [u8],
53 mut offset: u64,
54) -> io::Result<()> {
55 loop {
56 match read_at(filelike, buf, offset) {
57 Ok(0) if !buf.is_empty() => {
58 return Err(io::Error::new(
59 io::ErrorKind::UnexpectedEof,
60 "failed to fill whole buffer",
61 ))
62 }
63 Ok(nread) => {
64 offset = offset
65 .checked_add(nread.try_into().unwrap())
66 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "offset overflow"))?;
67 buf = &mut buf[nread..];
68 if buf.is_empty() {
69 return Ok(());
70 }
71 }
72 Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
73 Err(err) => return Err(err),
74 }
75 }
76}
77
78pub fn read_vectored_at<'a, Filelike: AsFilelike>(
80 filelike: &Filelike,
81 bufs: &mut [IoSliceMut],
82 offset: u64,
83) -> io::Result<usize> {
84 let buf = bufs
85 .iter_mut()
86 .find(|b| !b.is_empty())
87 .map_or(&mut [][..], |b| &mut **b);
88 read_at(filelike, buf, offset)
89}
90
91pub fn read_exact_vectored_at<'a, Filelike: AsFilelike>(
93 filelike: &Filelike,
94 mut bufs: &mut [IoSliceMut],
95 mut offset: u64,
96) -> io::Result<()> {
97 while !bufs.is_empty() {
98 match read_vectored_at(filelike, bufs, offset) {
99 Ok(nread) => {
100 offset = offset
101 .checked_add(nread.try_into().unwrap())
102 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "offset overflow"))?;
103 bufs = advance_mut(bufs, nread);
104 }
105 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
106 Err(e) => return Err(e),
107 }
108 }
109 Ok(())
110}
111
112#[inline]
114pub fn is_read_vectored_at<'a, Filelike: AsFilelike>(_filelike: &Filelike) -> bool {
115 false
116}
117
118#[cfg(feature = "io-streams")]
120pub fn read_via_stream_at<'a, Filelike: AsFilelike>(
121 filelike: &Filelike,
122 offset: u64,
123) -> io::Result<StreamReader> {
124 if let Ok(file) = filelike
127 .as_filelike_view::<File>()
128 .reopen(OpenOptions::new().read(true))
129 {
130 if offset != 0 {
131 file.seek(SeekFrom::Start(offset))?;
132 }
133 return Ok(StreamReader::file(file));
134 }
135
136 StreamReader::piped_thread(Box::new(OwnedStreamer::new(
138 filelike.as_filelike_view::<File>().try_clone()?,
139 offset,
140 )))
141}
142
143#[inline]
145pub fn write_at<'a, Filelike: AsFilelike>(
146 filelike: &Filelike,
147 buf: &[u8],
148 offset: u64,
149) -> io::Result<usize> {
150 filelike.as_filelike_view::<File>().seek_write(buf, offset)
151}
152
153pub fn write_all_at<'a, Filelike: AsFilelike>(
155 filelike: &Filelike,
156 mut buf: &[u8],
157 mut offset: u64,
158) -> io::Result<()> {
159 loop {
160 match write_at(filelike, buf, offset) {
161 Ok(nwritten) => {
162 offset = offset
163 .checked_add(nwritten.try_into().unwrap())
164 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "offset overflow"))?;
165 buf = &buf[nwritten..];
166 if buf.is_empty() {
167 return Ok(());
168 }
169 }
170 Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
171 Err(err) => return Err(err),
172 }
173 }
174}
175
176pub fn write_vectored_at<'a, Filelike: AsFilelike>(
178 filelike: &Filelike,
179 bufs: &[IoSlice],
180 offset: u64,
181) -> io::Result<usize> {
182 let buf = bufs
183 .iter()
184 .find(|b| !b.is_empty())
185 .map_or(&[][..], |b| &**b);
186 write_at(filelike, buf, offset)
187}
188
189pub fn write_all_vectored_at<'a, Filelike: AsFilelike>(
191 filelike: &Filelike,
192 mut bufs: &mut [IoSlice],
193 mut offset: u64,
194) -> io::Result<()> {
195 while !bufs.is_empty() {
196 match write_vectored_at(filelike, bufs, offset) {
197 Ok(nwritten) => {
198 offset = offset
199 .checked_add(nwritten.try_into().unwrap())
200 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "offset overflow"))?;
201 bufs = advance(bufs, nwritten);
202 }
203 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
204 Err(e) => return Err(e),
205 }
206 }
207 Ok(())
208}
209
210#[inline]
212pub fn is_write_vectored_at<'a, Filelike: AsFilelike>(_filelike: &Filelike) -> bool {
213 false
214}
215
216fn advance<'a, 'b>(bufs: &'b mut [IoSlice<'a>], n: usize) -> &'b mut [IoSlice<'a>] {
220 let mut remove = 0;
222 let mut accumulated_len = 0;
224 for buf in bufs.iter() {
225 if accumulated_len + buf.len() > n {
226 break;
227 } else {
228 accumulated_len += buf.len();
229 remove += 1;
230 }
231 }
232
233 #[allow(clippy::indexing_slicing)]
234 let bufs = &mut bufs[remove..];
235 if let Some(first) = bufs.first_mut() {
236 let advance_by = n - accumulated_len;
237 let mut ptr = first.as_ptr();
238 let mut len = first.len();
239 unsafe {
240 ptr = ptr.add(advance_by);
241 len -= advance_by;
242 *first = IoSlice::<'a>::new(slice::from_raw_parts::<'a>(ptr, len));
243 }
244 }
245 bufs
246}
247
248fn advance_mut<'a, 'b>(bufs: &'b mut [IoSliceMut<'a>], n: usize) -> &'b mut [IoSliceMut<'a>] {
252 let mut remove = 0;
254 let mut accumulated_len = 0;
256 for buf in bufs.iter() {
257 if accumulated_len + buf.len() > n {
258 break;
259 } else {
260 accumulated_len += buf.len();
261 remove += 1;
262 }
263 }
264
265 #[allow(clippy::indexing_slicing)]
266 let bufs = &mut bufs[remove..];
267 if let Some(first) = bufs.first_mut() {
268 let advance_by = n - accumulated_len;
269 let mut ptr = first.as_mut_ptr();
270 let mut len = first.len();
271 unsafe {
272 ptr = ptr.add(advance_by);
273 len -= advance_by;
274 *first = IoSliceMut::<'a>::new(slice::from_raw_parts_mut::<'a>(ptr, len));
275 }
276 }
277 bufs
278}