1use std::fs;
2use std::io::{self, Read, Seek, Write};
3use std::path::{Path, PathBuf};
4
5#[cfg(rustc_1_75)]
7use std::{fs::FileTimes, time::SystemTime};
8
9use crate::errors::{Error, ErrorKind};
10use crate::OpenOptions;
11
12#[derive(Debug)]
17pub struct File {
18 file: fs::File,
19 path: PathBuf,
20}
21
22pub(crate) fn open(path: &Path) -> Result<std::fs::File, impl FnOnce(PathBuf) -> io::Error> {
25 fs::File::open(path).map_err(|err| |path| Error::build(err, ErrorKind::OpenFile, path))
26}
27
28pub(crate) fn create(path: &Path) -> Result<std::fs::File, impl FnOnce(PathBuf) -> io::Error> {
30 fs::File::create(path).map_err(|err| |path| Error::build(err, ErrorKind::CreateFile, path))
31}
32
33impl File {
37 pub fn open<P>(path: P) -> Result<Self, io::Error>
41 where
42 P: Into<PathBuf>,
43 {
44 let path = path.into();
45 match open(&path) {
46 Ok(file) => Ok(File::from_parts(file, path)),
47 Err(err_gen) => Err(err_gen(path)),
48 }
49 }
50
51 pub fn create<P>(path: P) -> Result<Self, io::Error>
55 where
56 P: Into<PathBuf>,
57 {
58 let path = path.into();
59 match create(&path) {
60 Ok(file) => Ok(File::from_parts(file, path)),
61 Err(err_gen) => Err(err_gen(path)),
62 }
63 }
64
65 pub fn create_new<P>(path: P) -> Result<Self, io::Error>
69 where
70 P: Into<PathBuf>,
71 {
72 let path = path.into();
73 match fs::OpenOptions::new()
75 .read(true)
76 .write(true)
77 .create_new(true)
78 .open(&path)
79 {
80 Ok(file) => Ok(File::from_parts(file, path)),
81 Err(err) => Err(Error::build(err, ErrorKind::CreateFile, path)),
82 }
83 }
84
85 pub fn options() -> OpenOptions {
89 OpenOptions::new()
90 }
91
92 pub fn sync_all(&self) -> Result<(), io::Error> {
96 self.file
97 .sync_all()
98 .map_err(|source| self.error(source, ErrorKind::SyncFile))
99 }
100
101 pub fn sync_data(&self) -> Result<(), io::Error> {
105 self.file
106 .sync_data()
107 .map_err(|source| self.error(source, ErrorKind::SyncFile))
108 }
109
110 pub fn set_len(&self, size: u64) -> Result<(), io::Error> {
114 self.file
115 .set_len(size)
116 .map_err(|source| self.error(source, ErrorKind::SetLen))
117 }
118
119 pub fn metadata(&self) -> Result<fs::Metadata, io::Error> {
123 self.file
124 .metadata()
125 .map_err(|source| self.error(source, ErrorKind::Metadata))
126 }
127
128 pub fn try_clone(&self) -> Result<Self, io::Error> {
134 self.file
135 .try_clone()
136 .map(|file| File {
137 file,
138 path: self.path.clone(),
139 })
140 .map_err(|source| self.error(source, ErrorKind::Clone))
141 }
142
143 pub fn set_permissions(&self, perm: fs::Permissions) -> Result<(), io::Error> {
147 self.file
148 .set_permissions(perm)
149 .map_err(|source| self.error(source, ErrorKind::SetPermissions))
150 }
151}
152
153#[cfg(rustc_1_75)]
155impl File {
156 pub fn set_times(&self, times: FileTimes) -> Result<(), io::Error> {
160 self.file
161 .set_times(times)
162 .map_err(|source| self.error(source, ErrorKind::SetTimes))
163 }
164
165 pub fn set_modified(&self, time: SystemTime) -> Result<(), io::Error> {
169 self.file
170 .set_modified(time)
171 .map_err(|source| self.error(source, ErrorKind::SetModified))
172 }
173}
174
175#[cfg(rustc_1_89)]
177impl File {
178 pub fn lock(&self) -> Result<(), io::Error> {
182 self.file
183 .lock()
184 .map_err(|source| self.error(source, ErrorKind::Lock))
185 }
186
187 pub fn lock_shared(&self) -> Result<(), io::Error> {
191 self.file
192 .lock_shared()
193 .map_err(|source| self.error(source, ErrorKind::Lock))
194 }
195
196 pub fn try_lock(&self) -> Result<(), fs::TryLockError> {
200 self.file.try_lock()
201 }
202
203 pub fn try_lock_shared(&self) -> Result<(), fs::TryLockError> {
207 self.file.try_lock_shared()
208 }
209
210 pub fn unlock(&self) -> Result<(), io::Error> {
214 self.file
215 .unlock()
216 .map_err(|source| self.error(source, ErrorKind::Unlock))
217 }
218}
219
220impl File {
225 pub fn from_parts<P>(file: fs::File, path: P) -> Self
227 where
228 P: Into<PathBuf>,
229 {
230 File {
231 file,
232 path: path.into(),
233 }
234 }
235
236 pub fn into_parts(self) -> (fs::File, PathBuf) {
238 (self.file, self.path)
239 }
240
241 pub fn into_file(self) -> fs::File {
244 self.file
245 }
246
247 pub fn into_path(self) -> PathBuf {
250 self.path
251 }
252
253 pub fn file(&self) -> &fs::File {
257 &self.file
258 }
259
260 pub fn file_mut(&mut self) -> &mut fs::File {
264 &mut self.file
265 }
266
267 pub fn path(&self) -> &Path {
269 &self.path
270 }
271
272 fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error {
274 Error::build(source, kind, &self.path)
275 }
276}
277
278impl Read for File {
279 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
280 self.file
281 .read(buf)
282 .map_err(|source| self.error(source, ErrorKind::Read))
283 }
284
285 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
286 self.file
287 .read_vectored(bufs)
288 .map_err(|source| self.error(source, ErrorKind::Read))
289 }
290}
291
292impl Read for &File {
293 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
294 (&self.file)
295 .read(buf)
296 .map_err(|source| self.error(source, ErrorKind::Read))
297 }
298
299 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
300 (&self.file)
301 .read_vectored(bufs)
302 .map_err(|source| self.error(source, ErrorKind::Read))
303 }
304}
305
306impl From<File> for fs::File {
307 fn from(file: File) -> Self {
308 file.into_file()
309 }
310}
311
312impl Seek for File {
313 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
314 self.file
315 .seek(pos)
316 .map_err(|source| self.error(source, ErrorKind::Seek))
317 }
318}
319
320impl Seek for &File {
321 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
322 (&self.file)
323 .seek(pos)
324 .map_err(|source| self.error(source, ErrorKind::Seek))
325 }
326}
327
328impl Write for File {
329 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
330 self.file
331 .write(buf)
332 .map_err(|source| self.error(source, ErrorKind::Write))
333 }
334
335 fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
336 self.file
337 .write_vectored(bufs)
338 .map_err(|source| self.error(source, ErrorKind::Write))
339 }
340
341 fn flush(&mut self) -> std::io::Result<()> {
342 self.file
343 .flush()
344 .map_err(|source| self.error(source, ErrorKind::Flush))
345 }
346}
347
348impl Write for &File {
349 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
350 (&self.file)
351 .write(buf)
352 .map_err(|source| self.error(source, ErrorKind::Write))
353 }
354
355 fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
356 (&self.file)
357 .write_vectored(bufs)
358 .map_err(|source| self.error(source, ErrorKind::Write))
359 }
360
361 fn flush(&mut self) -> std::io::Result<()> {
362 (&self.file)
363 .flush()
364 .map_err(|source| self.error(source, ErrorKind::Flush))
365 }
366}
367
368#[cfg(unix)]
369mod unix {
370 use crate::os::unix::fs::FileExt;
371 use crate::ErrorKind;
372 use std::io;
373 use std::os::unix::fs::FileExt as _;
374 use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
375
376 impl AsRawFd for crate::File {
377 fn as_raw_fd(&self) -> RawFd {
378 self.file().as_raw_fd()
379 }
380 }
381
382 impl IntoRawFd for crate::File {
383 fn into_raw_fd(self) -> RawFd {
384 self.file.into_raw_fd()
385 }
386 }
387
388 impl FileExt for crate::File {
389 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
390 self.file()
391 .read_at(buf, offset)
392 .map_err(|err| self.error(err, ErrorKind::ReadAt))
393 }
394 fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
395 self.file()
396 .write_at(buf, offset)
397 .map_err(|err| self.error(err, ErrorKind::WriteAt))
398 }
399 }
400
401 #[cfg(rustc_1_63)]
402 mod io_safety {
403 use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
404
405 impl AsFd for crate::File {
406 fn as_fd(&self) -> BorrowedFd<'_> {
407 self.file().as_fd()
408 }
409 }
410
411 impl From<crate::File> for OwnedFd {
412 fn from(file: crate::File) -> Self {
413 file.into_file().into()
414 }
415 }
416 }
417}
418
419#[cfg(windows)]
420mod windows {
421 use crate::os::windows::fs::FileExt;
422 use crate::ErrorKind;
423 use std::io;
424 use std::os::windows::{
425 fs::FileExt as _,
426 io::{AsRawHandle, IntoRawHandle, RawHandle},
427 };
428
429 impl FileExt for crate::File {
430 fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
431 self.file()
432 .seek_read(buf, offset)
433 .map_err(|err| self.error(err, ErrorKind::SeekRead))
434 }
435
436 fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
437 self.file()
438 .seek_write(buf, offset)
439 .map_err(|err| self.error(err, ErrorKind::SeekWrite))
440 }
441 }
442
443 impl AsRawHandle for crate::File {
444 fn as_raw_handle(&self) -> RawHandle {
445 self.file().as_raw_handle()
446 }
447 }
448
449 impl IntoRawHandle for crate::File {
454 fn into_raw_handle(self) -> RawHandle {
455 self.file.into_raw_handle()
456 }
457 }
458
459 #[cfg(rustc_1_63)]
460 mod io_safety {
461 use std::os::windows::io::{AsHandle, BorrowedHandle, OwnedHandle};
462
463 impl AsHandle for crate::File {
464 fn as_handle(&self) -> BorrowedHandle<'_> {
465 self.file().as_handle()
466 }
467 }
468
469 impl From<crate::File> for OwnedHandle {
470 fn from(file: crate::File) -> Self {
471 file.into_parts().0.into()
472 }
473 }
474 }
475}