1use std::fs;
2use std::io::{self, Read, Seek, Write};
3use std::path::{Path, PathBuf};
4
5use crate::errors::{Error, ErrorKind};
6use crate::OpenOptions;
7
8#[derive(Debug)]
13pub struct File {
14 file: fs::File,
15 path: PathBuf,
16}
17
18pub(crate) fn open(path: &Path) -> Result<std::fs::File, impl FnOnce(PathBuf) -> io::Error> {
21 fs::File::open(path).map_err(|err| |path| Error::build(err, ErrorKind::OpenFile, path))
22}
23
24pub(crate) fn create(path: &Path) -> Result<std::fs::File, impl FnOnce(PathBuf) -> io::Error> {
26 fs::File::create(path).map_err(|err| |path| Error::build(err, ErrorKind::CreateFile, path))
27}
28
29impl File {
33 pub fn open<P>(path: P) -> Result<Self, io::Error>
37 where
38 P: Into<PathBuf>,
39 {
40 let path = path.into();
41 match open(&path) {
42 Ok(file) => Ok(File::from_parts(file, path)),
43 Err(err_gen) => Err(err_gen(path)),
44 }
45 }
46
47 pub fn create<P>(path: P) -> Result<Self, io::Error>
51 where
52 P: Into<PathBuf>,
53 {
54 let path = path.into();
55 match create(&path) {
56 Ok(file) => Ok(File::from_parts(file, path)),
57 Err(err_gen) => Err(err_gen(path)),
58 }
59 }
60
61 pub fn create_new<P>(path: P) -> Result<Self, io::Error>
65 where
66 P: Into<PathBuf>,
67 {
68 let path = path.into();
69 match fs::OpenOptions::new()
71 .read(true)
72 .write(true)
73 .create_new(true)
74 .open(&path)
75 {
76 Ok(file) => Ok(File::from_parts(file, path)),
77 Err(err) => Err(Error::build(err, ErrorKind::CreateFile, path)),
78 }
79 }
80
81 pub fn options() -> OpenOptions {
85 OpenOptions::new()
86 }
87
88 pub fn sync_all(&self) -> Result<(), io::Error> {
92 self.file
93 .sync_all()
94 .map_err(|source| self.error(source, ErrorKind::SyncFile))
95 }
96
97 pub fn sync_data(&self) -> Result<(), io::Error> {
101 self.file
102 .sync_data()
103 .map_err(|source| self.error(source, ErrorKind::SyncFile))
104 }
105
106 pub fn set_len(&self, size: u64) -> Result<(), io::Error> {
110 self.file
111 .set_len(size)
112 .map_err(|source| self.error(source, ErrorKind::SetLen))
113 }
114
115 pub fn metadata(&self) -> Result<fs::Metadata, io::Error> {
119 self.file
120 .metadata()
121 .map_err(|source| self.error(source, ErrorKind::Metadata))
122 }
123
124 pub fn try_clone(&self) -> Result<Self, io::Error> {
130 self.file
131 .try_clone()
132 .map(|file| File {
133 file,
134 path: self.path.clone(),
135 })
136 .map_err(|source| self.error(source, ErrorKind::Clone))
137 }
138
139 pub fn set_permissions(&self, perm: fs::Permissions) -> Result<(), io::Error> {
143 self.file
144 .set_permissions(perm)
145 .map_err(|source| self.error(source, ErrorKind::SetPermissions))
146 }
147}
148
149impl File {
154 pub fn from_parts<P>(file: fs::File, path: P) -> Self
156 where
157 P: Into<PathBuf>,
158 {
159 File {
160 file,
161 path: path.into(),
162 }
163 }
164
165 pub fn into_parts(self) -> (fs::File, PathBuf) {
167 (self.file, self.path)
168 }
169
170 pub fn into_file(self) -> fs::File {
173 self.file
174 }
175
176 pub fn into_path(self) -> PathBuf {
179 self.path
180 }
181
182 pub fn file(&self) -> &fs::File {
186 &self.file
187 }
188
189 pub fn file_mut(&mut self) -> &mut fs::File {
193 &mut self.file
194 }
195
196 pub fn path(&self) -> &Path {
198 &self.path
199 }
200
201 fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error {
203 Error::build(source, kind, &self.path)
204 }
205}
206
207impl Read for File {
208 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
209 self.file
210 .read(buf)
211 .map_err(|source| self.error(source, ErrorKind::Read))
212 }
213
214 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
215 self.file
216 .read_vectored(bufs)
217 .map_err(|source| self.error(source, ErrorKind::Read))
218 }
219}
220
221impl Read for &File {
222 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
223 (&self.file)
224 .read(buf)
225 .map_err(|source| self.error(source, ErrorKind::Read))
226 }
227
228 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
229 (&self.file)
230 .read_vectored(bufs)
231 .map_err(|source| self.error(source, ErrorKind::Read))
232 }
233}
234
235impl From<File> for fs::File {
236 fn from(file: File) -> Self {
237 file.into_file()
238 }
239}
240
241impl Seek for File {
242 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
243 self.file
244 .seek(pos)
245 .map_err(|source| self.error(source, ErrorKind::Seek))
246 }
247}
248
249impl Seek for &File {
250 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
251 (&self.file)
252 .seek(pos)
253 .map_err(|source| self.error(source, ErrorKind::Seek))
254 }
255}
256
257impl Write for File {
258 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
259 self.file
260 .write(buf)
261 .map_err(|source| self.error(source, ErrorKind::Write))
262 }
263
264 fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
265 self.file
266 .write_vectored(bufs)
267 .map_err(|source| self.error(source, ErrorKind::Write))
268 }
269
270 fn flush(&mut self) -> std::io::Result<()> {
271 self.file
272 .flush()
273 .map_err(|source| self.error(source, ErrorKind::Flush))
274 }
275}
276
277impl Write for &File {
278 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
279 (&self.file)
280 .write(buf)
281 .map_err(|source| self.error(source, ErrorKind::Write))
282 }
283
284 fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
285 (&self.file)
286 .write_vectored(bufs)
287 .map_err(|source| self.error(source, ErrorKind::Write))
288 }
289
290 fn flush(&mut self) -> std::io::Result<()> {
291 (&self.file)
292 .flush()
293 .map_err(|source| self.error(source, ErrorKind::Flush))
294 }
295}
296
297#[cfg(unix)]
298mod unix {
299 use crate::os::unix::fs::FileExt;
300 use crate::ErrorKind;
301 use std::io;
302 use std::os::unix::fs::FileExt as _;
303 use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
304
305 impl AsRawFd for crate::File {
306 fn as_raw_fd(&self) -> RawFd {
307 self.file().as_raw_fd()
308 }
309 }
310
311 impl IntoRawFd for crate::File {
312 fn into_raw_fd(self) -> RawFd {
313 self.file.into_raw_fd()
314 }
315 }
316
317 impl FileExt for crate::File {
318 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
319 self.file()
320 .read_at(buf, offset)
321 .map_err(|err| self.error(err, ErrorKind::ReadAt))
322 }
323 fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
324 self.file()
325 .write_at(buf, offset)
326 .map_err(|err| self.error(err, ErrorKind::WriteAt))
327 }
328 }
329
330 #[cfg(rustc_1_63)]
331 mod io_safety {
332 use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
333
334 impl AsFd for crate::File {
335 fn as_fd(&self) -> BorrowedFd<'_> {
336 self.file().as_fd()
337 }
338 }
339
340 impl From<crate::File> for OwnedFd {
341 fn from(file: crate::File) -> Self {
342 file.into_file().into()
343 }
344 }
345 }
346}
347
348#[cfg(windows)]
349mod windows {
350 use crate::os::windows::fs::FileExt;
351 use crate::ErrorKind;
352 use std::io;
353 use std::os::windows::{
354 fs::FileExt as _,
355 io::{AsRawHandle, IntoRawHandle, RawHandle},
356 };
357
358 impl FileExt for crate::File {
359 fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
360 self.file()
361 .seek_read(buf, offset)
362 .map_err(|err| self.error(err, ErrorKind::SeekRead))
363 }
364
365 fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
366 self.file()
367 .seek_write(buf, offset)
368 .map_err(|err| self.error(err, ErrorKind::SeekWrite))
369 }
370 }
371
372 impl AsRawHandle for crate::File {
373 fn as_raw_handle(&self) -> RawHandle {
374 self.file().as_raw_handle()
375 }
376 }
377
378 impl IntoRawHandle for crate::File {
383 fn into_raw_handle(self) -> RawHandle {
384 self.file.into_raw_handle()
385 }
386 }
387
388 #[cfg(rustc_1_63)]
389 mod io_safety {
390 use std::os::windows::io::{AsHandle, BorrowedHandle, OwnedHandle};
391
392 impl AsHandle for crate::File {
393 fn as_handle(&self) -> BorrowedHandle<'_> {
394 self.file().as_handle()
395 }
396 }
397
398 impl From<crate::File> for OwnedHandle {
399 fn from(file: crate::File) -> Self {
400 file.into_parts().0.into()
401 }
402 }
403 }
404}