cap_primitives/fs/
file.rs1use std::io;
2
3#[cfg(unix)]
5pub trait FileExt {
6    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
8
9    #[cfg(unix_file_vectored_at)]
11    fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
12        default_read_vectored(|b| self.read_at(b, offset), bufs)
13    }
14
15    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
17        while !buf.is_empty() {
18            match self.read_at(buf, offset) {
19                Ok(0) => break,
20                Ok(n) => {
21                    let tmp = buf;
22                    buf = &mut tmp[n..];
23                    offset += n as u64;
24                }
25                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
26                Err(e) => return Err(e),
27            }
28        }
29        if !buf.is_empty() {
30            Err(io::Error::new(
31                io::ErrorKind::UnexpectedEof,
32                "failed to fill whole buffer",
33            ))
34        } else {
35            Ok(())
36        }
37    }
38
39    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
41
42    #[cfg(unix_file_vectored_at)]
44    fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
45        default_write_vectored(|b| self.write_at(b, offset), bufs)
46    }
47
48    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
50        while !buf.is_empty() {
51            match self.write_at(buf, offset) {
52                Ok(0) => {
53                    return Err(io::Error::new(
54                        io::ErrorKind::WriteZero,
55                        "failed to write whole buffer",
56                    ));
57                }
58                Ok(n) => {
59                    buf = &buf[n..];
60                    offset += n as u64
61                }
62                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
63                Err(e) => return Err(e),
64            }
65        }
66        Ok(())
67    }
68}
69
70#[cfg(unix_file_vectored_at)]
71fn default_read_vectored<F>(read: F, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize>
72where
73    F: FnOnce(&mut [u8]) -> io::Result<usize>,
74{
75    let buf = bufs
76        .iter_mut()
77        .find(|b| !b.is_empty())
78        .map_or(&mut [][..], |b| &mut **b);
79    read(buf)
80}
81
82#[cfg(unix_file_vectored_at)]
83fn default_write_vectored<F>(write: F, bufs: &[io::IoSlice<'_>]) -> io::Result<usize>
84where
85    F: FnOnce(&[u8]) -> io::Result<usize>,
86{
87    let buf = bufs
88        .iter()
89        .find(|b| !b.is_empty())
90        .map_or(&[][..], |b| &**b);
91    write(buf)
92}
93
94#[cfg(target_os = "wasi")]
96pub trait FileExt {
97    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
99        let bufs = &mut [io::IoSliceMut::new(buf)];
100        self.read_vectored_at(bufs, offset)
101    }
102
103    fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize>;
105
106    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
108        while !buf.is_empty() {
109            match self.read_at(buf, offset) {
110                Ok(0) => break,
111                Ok(n) => {
112                    let tmp = buf;
113                    buf = &mut tmp[n..];
114                    offset += n as u64;
115                }
116                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
117                Err(e) => return Err(e),
118            }
119        }
120        if !buf.is_empty() {
121            Err(io::Error::new(
122                io::ErrorKind::UnexpectedEof,
123                "failed to fill whole buffer",
124            ))
125        } else {
126            Ok(())
127        }
128    }
129
130    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
132        let bufs = &[io::IoSlice::new(buf)];
133        self.write_vectored_at(bufs, offset)
134    }
135
136    fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize>;
138
139    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
141        while !buf.is_empty() {
142            match self.write_at(buf, offset) {
143                Ok(0) => {
144                    return Err(io::Error::new(
145                        io::ErrorKind::WriteZero,
146                        "failed to write whole buffer",
147                    ));
148                }
149                Ok(n) => {
150                    buf = &buf[n..];
151                    offset += n as u64
152                }
153                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
154                Err(e) => return Err(e),
155            }
156        }
157        Ok(())
158    }
159
160    fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
162
163    fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
165
166    fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
168
169    fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
171
172    fn create_directory<P: AsRef<std::path::Path>>(&self, dir: P) -> io::Result<()>;
174
175    fn read_link<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<std::path::PathBuf>;
177
178    fn metadata_at<P: AsRef<std::path::Path>>(
180        &self,
181        lookup_flags: u32,
182        path: P,
183    ) -> io::Result<std::fs::Metadata>;
184
185    fn remove_file<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<()>;
187
188    fn remove_directory<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<()>;
190}
191
192#[cfg(windows)]
194pub trait FileExt {
195    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
197
198    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
200}