#[cfg(not(any(
windows,
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "redox",
)))]
use posish::fs::fadvise;
#[cfg(not(any(windows, target_os = "netbsd", target_os = "redox")))]
use posish::fs::posix_fallocate;
#[cfg(any(target_os = "ios", target_os = "macos"))]
use posish::fs::rdadvise;
#[cfg(not(windows))]
use posish::fs::tell;
#[cfg(not(any(windows, target_os = "ios", target_os = "macos", target_os = "redox")))]
use posish::fs::{preadv, pwritev};
#[cfg(unix)]
use std::os::unix::{fs::FileExt, io::AsRawFd};
#[cfg(target_os = "wasi")]
use std::os::wasi::{fs::FileExt, io::AsRawFd};
use std::{
convert::TryInto,
fmt::Arguments,
io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write},
slice,
};
use unsafe_io::AsUnsafeFile;
#[cfg(windows)]
use {cap_fs_ext::Reopen, std::fs, std::os::windows::fs::FileExt, unsafe_io::UnsafeFile};
#[cfg(not(any(
windows,
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "redox"
)))]
#[derive(Debug, Eq, PartialEq, Hash)]
#[repr(i32)]
pub enum Advice {
Normal = posish::fs::Advice::Normal as i32,
Sequential = posish::fs::Advice::Sequential as i32,
Random = posish::fs::Advice::Random as i32,
WillNeed = posish::fs::Advice::WillNeed as i32,
DontNeed = posish::fs::Advice::DontNeed as i32,
NoReuse = posish::fs::Advice::NoReuse as i32,
}
#[cfg(any(
windows,
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "redox"
))]
#[derive(Debug, Eq, PartialEq, Hash)]
pub enum Advice {
Normal,
Sequential,
Random,
WillNeed,
DontNeed,
NoReuse,
}
pub trait FileIoExt {
fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()>;
fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
fn read(&self, buf: &mut [u8]) -> io::Result<usize>;
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()>;
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()>;
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize>;
fn read_exact_vectored(&self, mut bufs: &mut [IoSliceMut]) -> io::Result<()> {
while !bufs.is_empty() {
match self.read_vectored(bufs) {
Ok(0) => break,
Ok(nread) => bufs = advance_mut(bufs, nread),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
Err(e) => return Err(e),
}
}
Ok(())
}
fn read_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<usize> {
let buf = bufs
.iter_mut()
.find(|b| !b.is_empty())
.map_or(&mut [][..], |b| &mut **b);
self.read_at(buf, offset)
}
fn read_exact_vectored_at(
&self,
mut bufs: &mut [IoSliceMut],
mut offset: u64,
) -> io::Result<()> {
while !bufs.is_empty() {
match self.read_vectored_at(bufs, offset) {
Ok(0) => break,
Ok(nread) => {
offset = offset
.checked_add(nread.try_into().unwrap())
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "offset overflow"))?;
bufs = advance_mut(bufs, nread);
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
Err(e) => return Err(e),
}
}
Ok(())
}
#[inline]
fn is_read_vectored_at(&self) -> bool {
false
}
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize>;
fn read_to_end_at(&self, buf: &mut Vec<u8>, offset: u64) -> io::Result<usize>;
fn read_to_string(&self, buf: &mut String) -> io::Result<usize>;
fn read_to_string_at(&self, buf: &mut String, offset: u64) -> io::Result<usize>;
fn peek(&self, buf: &mut [u8]) -> io::Result<usize>;
fn write(&self, buf: &[u8]) -> io::Result<usize>;
fn write_all(&self, buf: &[u8]) -> io::Result<()>;
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
fn write_all_at(&self, buf: &[u8], offset: u64) -> io::Result<()>;
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize>;
fn write_all_vectored(&self, mut bufs: &mut [IoSlice]) -> io::Result<()> {
while !bufs.is_empty() {
match self.write_vectored(bufs) {
Ok(nwritten) => bufs = advance(bufs, nwritten),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
Err(e) => return Err(e),
}
}
Ok(())
}
fn write_vectored_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result<usize> {
let buf = bufs
.iter()
.find(|b| !b.is_empty())
.map_or(&[][..], |b| &**b);
self.write_at(buf, offset)
}
fn write_all_vectored_at(&self, mut bufs: &mut [IoSlice], mut offset: u64) -> io::Result<()> {
while !bufs.is_empty() {
match self.write_vectored_at(bufs, offset) {
Ok(nwritten) => {
offset = offset
.checked_add(nwritten.try_into().unwrap())
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "offset overflow"))?;
bufs = advance(bufs, nwritten);
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
Err(e) => return Err(e),
}
}
Ok(())
}
#[inline]
fn is_write_vectored_at(&self) -> bool {
false
}
fn write_fmt(&self, fmt: Arguments) -> io::Result<()>;
fn flush(&self) -> io::Result<()>;
fn seek(&self, pos: SeekFrom) -> io::Result<u64>;
fn stream_position(&self) -> io::Result<u64>;
}
fn advance<'a, 'b>(bufs: &'b mut [IoSlice<'a>], n: usize) -> &'b mut [IoSlice<'a>] {
let mut remove = 0;
let mut accumulated_len = 0;
for buf in bufs.iter() {
if accumulated_len + buf.len() > n {
break;
} else {
accumulated_len += buf.len();
remove += 1;
}
}
#[allow(clippy::indexing_slicing)]
let bufs = &mut bufs[remove..];
if let Some(first) = bufs.first_mut() {
let advance_by = n - accumulated_len;
let mut ptr = first.as_ptr();
let mut len = first.len();
unsafe {
ptr = ptr.add(advance_by);
len -= advance_by;
*first = IoSlice::<'a>::new(slice::from_raw_parts::<'a>(ptr, len));
}
}
bufs
}
fn advance_mut<'a, 'b>(bufs: &'b mut [IoSliceMut<'a>], n: usize) -> &'b mut [IoSliceMut<'a>] {
let mut remove = 0;
let mut accumulated_len = 0;
for buf in bufs.iter() {
if accumulated_len + buf.len() > n {
break;
} else {
accumulated_len += buf.len();
remove += 1;
}
}
#[allow(clippy::indexing_slicing)]
let bufs = &mut bufs[remove..];
if let Some(first) = bufs.first_mut() {
let advance_by = n - accumulated_len;
let mut ptr = first.as_mut_ptr();
let mut len = first.len();
unsafe {
ptr = ptr.add(advance_by);
len -= advance_by;
*first = IoSliceMut::<'a>::new(slice::from_raw_parts_mut::<'a>(ptr, len));
}
}
bufs
}
#[cfg(not(windows))]
impl<T> FileIoExt for T
where
T: AsRawFd,
{
#[cfg(not(any(
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "redox"
)))]
#[inline]
fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> {
let advice = match advice {
Advice::WillNeed => posish::fs::Advice::WillNeed,
Advice::Normal => posish::fs::Advice::Normal,
Advice::Sequential => posish::fs::Advice::Sequential,
Advice::NoReuse => posish::fs::Advice::NoReuse,
Advice::Random => posish::fs::Advice::Random,
Advice::DontNeed => posish::fs::Advice::DontNeed,
};
fadvise(self, offset, len, advice)
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
#[inline]
fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> {
match advice {
Advice::WillNeed => (),
Advice::Normal
| Advice::Sequential
| Advice::NoReuse
| Advice::Random
| Advice::DontNeed => return Ok(()),
}
rdadvise(self, offset, len)
}
#[cfg(any(target_os = "netbsd", target_os = "redox"))]
#[inline]
fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> io::Result<()> {
Ok(())
}
#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
#[inline]
fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
posix_fallocate(self, offset, len)
}
#[cfg(target_os = "netbsd")]
fn allocate(&self, _offset: u64, _len: u64) -> io::Result<()> {
todo!("NetBSD 7.0 supports posix_fallocate; add bindings for it")
}
#[cfg(target_os = "redox")]
fn allocate(&self, _offset: u64, _len: u64) -> io::Result<()> {
todo!("figure out what to do on redox for posix_fallocate")
}
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
Read::read(&mut *self.as_file_view(), buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
Read::read_exact(&mut *self.as_file_view(), buf)
}
#[inline]
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
FileExt::read_at(&*self.as_file_view(), buf, offset)
}
#[inline]
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
FileExt::read_exact_at(&*self.as_file_view(), buf, offset)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
Read::read_vectored(&mut *self.as_file_view(), bufs)
}
#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
#[inline]
fn read_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<usize> {
preadv(self, bufs, offset)
}
#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
#[inline]
fn is_read_vectored_at(&self) -> bool {
true
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
Read::read_to_end(&mut *self.as_file_view(), buf)
}
#[inline]
fn read_to_end_at(&self, buf: &mut Vec<u8>, offset: u64) -> io::Result<usize> {
read_to_end_at(&self.as_file_view(), buf, offset)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
Read::read_to_string(&mut *self.as_file_view(), buf)
}
#[inline]
fn read_to_string_at(&self, buf: &mut String, offset: u64) -> io::Result<usize> {
read_to_string_at(&self.as_file_view(), buf, offset)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
let pos = self.seek(SeekFrom::Current(0))?;
self.read_at(buf, pos)
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
Write::write(&mut *self.as_file_view(), buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
Write::write_all(&mut *self.as_file_view(), buf)
}
#[inline]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
FileExt::write_at(&*self.as_file_view(), buf, offset)
}
#[inline]
fn write_all_at(&self, buf: &[u8], offset: u64) -> io::Result<()> {
FileExt::write_all_at(&*self.as_file_view(), buf, offset)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
Write::write_vectored(&mut *self.as_file_view(), bufs)
}
#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
#[inline]
fn write_vectored_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result<usize> {
pwritev(self, bufs, offset)
}
#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
#[inline]
fn is_write_vectored_at(&self) -> bool {
true
}
#[inline]
fn flush(&self) -> io::Result<()> {
Write::flush(&mut *self.as_file_view())
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
Write::write_fmt(&mut *self.as_file_view(), fmt)
}
#[inline]
fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
Seek::seek(&mut *self.as_file_view(), pos)
}
#[inline]
fn stream_position(&self) -> io::Result<u64> {
tell(self)
}
}
#[cfg(windows)]
impl FileIoExt for fs::File {
#[inline]
fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> io::Result<()> {
Ok(())
}
#[inline]
fn allocate(&self, _offset: u64, _len: u64) -> io::Result<()> {
Err(io::Error::new(
io::ErrorKind::PermissionDenied,
"file allocate is not supported on Windows",
))
}
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
Read::read(&mut *self.as_file_view(), buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
Read::read_exact(&mut *self.as_file_view(), buf)
}
#[inline]
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
let reopened = reopen(self)?;
reopened.seek_read(buf, offset)
}
#[inline]
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
let reopened = loop {
match reopen(self) {
Ok(file) => break file,
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
}
};
loop {
match reopened.seek(SeekFrom::Start(offset)) {
Ok(_) => break,
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
}
}
reopened.read_exact(buf)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
Read::read_vectored(&mut *self.as_file_view(), bufs)
}
#[inline]
fn read_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<usize> {
let reopened = reopen(self)?;
reopened.seek(SeekFrom::Start(offset))?;
reopened.read_vectored(bufs)
}
#[inline]
fn read_exact_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<()> {
let reopened = loop {
match reopen(self) {
Ok(file) => break file,
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
}
};
loop {
match reopened.seek(SeekFrom::Start(offset)) {
Ok(_) => break,
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
}
}
reopened.read_exact_vectored(bufs)
}
#[inline]
fn is_read_vectored_at(&self) -> bool {
true
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
Read::read_to_end(&mut *self.as_file_view(), buf)
}
#[inline]
fn read_to_end_at(&self, buf: &mut Vec<u8>, offset: u64) -> io::Result<usize> {
read_to_end_at(self, buf, offset)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
Read::read_to_string(&mut *self.as_file_view(), buf)
}
#[inline]
fn read_to_string_at(&self, buf: &mut String, offset: u64) -> io::Result<usize> {
read_to_string_at(self, buf, offset)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
let reopened = reopen_write(self)?;
reopened.read(buf)
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
Write::write(&mut *self.as_file_view(), buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
Write::write_all(&mut *self.as_file_view(), buf)
}
#[inline]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
let reopened = reopen_write(self)?;
reopened.seek_write(buf, offset)
}
#[inline]
fn write_all_at(&self, buf: &[u8], offset: u64) -> io::Result<()> {
let reopened = loop {
match reopen_write(self) {
Ok(file) => break file,
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
}
};
loop {
match reopened.seek(SeekFrom::Start(offset)) {
Ok(_) => break,
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
}
}
reopened.write_all(buf)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
Write::write_vectored(&mut *self.as_file_view(), bufs)
}
#[inline]
fn write_vectored_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result<usize> {
let reopened = reopen_write(self)?;
reopened.seek(SeekFrom::Start(offset))?;
reopened.write_vectored(bufs)
}
#[inline]
fn write_all_vectored_at(&self, bufs: &mut [IoSlice], offset: u64) -> io::Result<()> {
let reopened = loop {
match reopen_write(self) {
Ok(file) => break file,
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
}
};
loop {
match reopened.seek(SeekFrom::Start(offset)) {
Ok(_) => break,
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
}
}
reopened.write_all_vectored(bufs)
}
#[inline]
fn is_write_vectored_at(&self) -> bool {
true
}
#[inline]
fn flush(&self) -> io::Result<()> {
Write::flush(&mut *self.as_file_view())
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
Write::write_fmt(&mut *self.as_file_view(), fmt)
}
#[inline]
fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
Seek::seek(&mut *self.as_file_view(), pos)
}
#[inline]
fn stream_position(&self) -> io::Result<u64> {
Seek::seek(&mut *self.as_file_view(), SeekFrom::Current(0))
}
}
#[cfg(all(windows, feature = "cap_std_impls"))]
impl FileIoExt for cap_std::fs::File {
#[inline]
fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> {
self.as_file_view().advise(offset, len, advice)
}
#[inline]
fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
self.as_file_view().allocate(offset, len)
}
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_file_view().read(buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
self.as_file_view().read_exact(buf)
}
#[inline]
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.as_file_view().read_at(buf, offset)
}
#[inline]
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
self.as_file_view().read_exact_at(buf, offset)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
self.as_file_view().read_vectored(bufs)
}
#[inline]
fn read_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<usize> {
self.as_file_view().read_vectored_at(bufs, offset)
}
#[inline]
fn read_exact_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<()> {
self.as_file_view().read_exact_vectored_at(bufs, offset)
}
#[inline]
fn is_read_vectored_at(&self) -> bool {
self.as_file_view().is_read_vectored_at()
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.as_file_view().read_to_end(buf)
}
#[inline]
fn read_to_end_at(&self, buf: &mut Vec<u8>, offset: u64) -> io::Result<usize> {
read_to_end_at(&self.as_file_view(), buf, offset)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
self.as_file_view().read_to_string(buf)
}
#[inline]
fn read_to_string_at(&self, buf: &mut String, offset: u64) -> io::Result<usize> {
read_to_string_at(&self.as_file_view(), buf, offset)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_file_view().peek(buf)
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.as_file_view().write(buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
self.as_file_view().write_all(buf)
}
#[inline]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.as_file_view().write_at(buf, offset)
}
#[inline]
fn write_all_at(&self, buf: &[u8], offset: u64) -> io::Result<()> {
self.as_file_view().write_all_at(buf, offset)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
self.as_file_view().write_vectored(bufs)
}
#[inline]
fn write_vectored_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result<usize> {
self.as_file_view().write_vectored_at(bufs, offset)
}
#[inline]
fn write_all_vectored_at(&self, bufs: &mut [IoSlice], offset: u64) -> io::Result<()> {
self.as_file_view().write_all_vectored_at(bufs, offset)
}
#[inline]
fn is_write_vectored_at(&self) -> bool {
self.as_file_view().is_write_vectored_at()
}
#[inline]
fn flush(&self) -> io::Result<()> {
self.as_file_view().flush()
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
self.as_file_view().write_fmt(fmt)
}
#[inline]
fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
self.as_file_view().seek(pos)
}
#[inline]
fn stream_position(&self) -> io::Result<u64> {
self.as_file_view().stream_position()
}
}
#[cfg(all(windows, feature = "cap_std_impls_fs_utf8"))]
impl FileIoExt for cap_std::fs_utf8::File {
#[inline]
fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> {
self.as_file_view().advise(offset, len, advice)
}
#[inline]
fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
self.as_file_view().allocate(offset, len)
}
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_file_view().read(buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
self.as_file_view().read_exact(buf)
}
#[inline]
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.as_file_view().read_at(buf, offset)
}
#[inline]
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
self.as_file_view().read_exact_at(buf, offset)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
self.as_file_view().read_vectored(bufs)
}
#[inline]
fn read_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<usize> {
self.as_file_view().read_vectored_at(bufs, offset)
}
#[inline]
fn read_exact_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<()> {
self.as_file_view().read_exact_vectored_at(bufs, offset)
}
#[inline]
fn is_read_vectored_at(&self) -> bool {
self.as_file_view().is_read_vectored_at()
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.as_file_view().read_to_end(buf)
}
#[inline]
fn read_to_end_at(&self, buf: &mut Vec<u8>, offset: u64) -> io::Result<usize> {
read_to_end_at(&self.as_file_view(), buf, offset)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
self.as_file_view().read_to_string(buf)
}
#[inline]
fn read_to_string_at(&self, buf: &mut String, offset: u64) -> io::Result<usize> {
read_to_string_at(&self.as_file_view(), buf, offset)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_file_view().peek(buf)
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.as_file_view().write(buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
self.as_file_view().write_all(buf)
}
#[inline]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.as_file_view().write_at(buf, offset)
}
#[inline]
fn write_all_at(&self, buf: &[u8], offset: u64) -> io::Result<()> {
self.as_file_view().write_all_at(buf, offset)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
self.as_file_view().write_vectored(bufs)
}
#[inline]
fn write_vectored_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result<usize> {
self.as_file_view().write_vectored_at(bufs, offset)
}
#[inline]
fn write_all_vectored_at(&self, bufs: &mut [IoSlice], offset: u64) -> io::Result<()> {
self.as_file_view().write_all_vectored_at(bufs, offset)
}
#[inline]
fn is_write_vectored_at(&self) -> bool {
self.as_file_view().is_write_vectored_at()
}
#[inline]
fn flush(&self) -> io::Result<()> {
self.as_file_view().flush()
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
self.as_file_view().write_fmt(fmt)
}
#[inline]
fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
self.as_file_view().seek(pos)
}
#[inline]
fn stream_position(&self) -> io::Result<u64> {
self.as_file_view().stream_position()
}
}
#[cfg(windows)]
#[inline]
fn reopen<AUF: AsUnsafeFile>(as_auf: &AUF) -> io::Result<fs::File> {
let unsafe_file = as_auf.as_unsafe_file();
unsafe { _reopen(unsafe_file) }
}
#[cfg(windows)]
unsafe fn _reopen(unsafe_file: UnsafeFile) -> io::Result<fs::File> {
unsafe_file
.as_file_view()
.reopen(cap_fs_ext::OpenOptions::new().read(true))
}
#[cfg(windows)]
#[inline]
fn reopen_write<AUF: AsUnsafeFile>(as_auf: &AUF) -> io::Result<fs::File> {
let unsafe_file = as_auf.as_unsafe_file();
unsafe { _reopen_write(unsafe_file) }
}
#[cfg(windows)]
unsafe fn _reopen_write(unsafe_file: UnsafeFile) -> io::Result<fs::File> {
unsafe_file
.as_file_view()
.reopen(cap_fs_ext::OpenOptions::new().write(true))
}
fn read_to_end_at(file: &std::fs::File, buf: &mut Vec<u8>, offset: u64) -> io::Result<usize> {
let len = match file.metadata()?.len().checked_sub(offset) {
None => return Ok(0),
Some(len) => len,
};
buf.resize(
(buf.len() as u64)
.checked_add(len)
.unwrap_or(u64::MAX)
.try_into()
.unwrap_or(usize::MAX),
0_u8,
);
FileIoExt::read_exact_at(file, buf, offset)?;
Ok(len as usize)
}
fn read_to_string_at(file: &std::fs::File, buf: &mut String, offset: u64) -> io::Result<usize> {
let len = match file.metadata()?.len().checked_sub(offset) {
None => return Ok(0),
Some(len) => len,
};
let mut tmp = vec![0_u8; len.try_into().unwrap_or(usize::MAX)];
FileIoExt::read_exact_at(file, &mut tmp, offset)?;
let s = String::from_utf8(tmp).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidData,
"stream did not contain valid UTF-8",
)
})?;
buf.push_str(&s);
Ok(len as usize)
}
fn _file_io_ext_can_be_trait_object(_: &dyn FileIoExt) {}