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
149#[cfg(rustc_1_89)]
151impl File {
152 pub fn lock(&self) -> Result<(), io::Error> {
156 self.file
157 .lock()
158 .map_err(|source| self.error(source, ErrorKind::Lock))
159 }
160
161 pub fn lock_shared(&self) -> Result<(), io::Error> {
165 self.file
166 .lock_shared()
167 .map_err(|source| self.error(source, ErrorKind::Lock))
168 }
169
170 pub fn try_lock(&self) -> Result<(), fs::TryLockError> {
174 self.file.try_lock()
175 }
176
177 pub fn try_lock_shared(&self) -> Result<(), fs::TryLockError> {
181 self.file.try_lock_shared()
182 }
183
184 pub fn unlock(&self) -> Result<(), io::Error> {
188 self.file
189 .unlock()
190 .map_err(|source| self.error(source, ErrorKind::Unlock))
191 }
192}
193
194impl File {
199 pub fn from_parts<P>(file: fs::File, path: P) -> Self
201 where
202 P: Into<PathBuf>,
203 {
204 File {
205 file,
206 path: path.into(),
207 }
208 }
209
210 pub fn into_parts(self) -> (fs::File, PathBuf) {
212 (self.file, self.path)
213 }
214
215 pub fn into_file(self) -> fs::File {
218 self.file
219 }
220
221 pub fn into_path(self) -> PathBuf {
224 self.path
225 }
226
227 pub fn file(&self) -> &fs::File {
231 &self.file
232 }
233
234 pub fn file_mut(&mut self) -> &mut fs::File {
238 &mut self.file
239 }
240
241 pub fn path(&self) -> &Path {
243 &self.path
244 }
245
246 fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error {
248 Error::build(source, kind, &self.path)
249 }
250}
251
252impl Read for File {
253 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
254 self.file
255 .read(buf)
256 .map_err(|source| self.error(source, ErrorKind::Read))
257 }
258
259 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
260 self.file
261 .read_vectored(bufs)
262 .map_err(|source| self.error(source, ErrorKind::Read))
263 }
264}
265
266impl Read for &File {
267 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
268 (&self.file)
269 .read(buf)
270 .map_err(|source| self.error(source, ErrorKind::Read))
271 }
272
273 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
274 (&self.file)
275 .read_vectored(bufs)
276 .map_err(|source| self.error(source, ErrorKind::Read))
277 }
278}
279
280impl From<File> for fs::File {
281 fn from(file: File) -> Self {
282 file.into_file()
283 }
284}
285
286impl Seek for File {
287 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
288 self.file
289 .seek(pos)
290 .map_err(|source| self.error(source, ErrorKind::Seek))
291 }
292}
293
294impl Seek for &File {
295 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
296 (&self.file)
297 .seek(pos)
298 .map_err(|source| self.error(source, ErrorKind::Seek))
299 }
300}
301
302impl Write for File {
303 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
304 self.file
305 .write(buf)
306 .map_err(|source| self.error(source, ErrorKind::Write))
307 }
308
309 fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
310 self.file
311 .write_vectored(bufs)
312 .map_err(|source| self.error(source, ErrorKind::Write))
313 }
314
315 fn flush(&mut self) -> std::io::Result<()> {
316 self.file
317 .flush()
318 .map_err(|source| self.error(source, ErrorKind::Flush))
319 }
320}
321
322impl Write for &File {
323 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
324 (&self.file)
325 .write(buf)
326 .map_err(|source| self.error(source, ErrorKind::Write))
327 }
328
329 fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
330 (&self.file)
331 .write_vectored(bufs)
332 .map_err(|source| self.error(source, ErrorKind::Write))
333 }
334
335 fn flush(&mut self) -> std::io::Result<()> {
336 (&self.file)
337 .flush()
338 .map_err(|source| self.error(source, ErrorKind::Flush))
339 }
340}
341
342#[cfg(unix)]
343mod unix {
344 use crate::os::unix::fs::FileExt;
345 use crate::ErrorKind;
346 use std::io;
347 use std::os::unix::fs::FileExt as _;
348 use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
349
350 impl AsRawFd for crate::File {
351 fn as_raw_fd(&self) -> RawFd {
352 self.file().as_raw_fd()
353 }
354 }
355
356 impl IntoRawFd for crate::File {
357 fn into_raw_fd(self) -> RawFd {
358 self.file.into_raw_fd()
359 }
360 }
361
362 impl FileExt for crate::File {
363 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
364 self.file()
365 .read_at(buf, offset)
366 .map_err(|err| self.error(err, ErrorKind::ReadAt))
367 }
368 fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
369 self.file()
370 .write_at(buf, offset)
371 .map_err(|err| self.error(err, ErrorKind::WriteAt))
372 }
373 }
374
375 #[cfg(rustc_1_63)]
376 mod io_safety {
377 use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
378
379 impl AsFd for crate::File {
380 fn as_fd(&self) -> BorrowedFd<'_> {
381 self.file().as_fd()
382 }
383 }
384
385 impl From<crate::File> for OwnedFd {
386 fn from(file: crate::File) -> Self {
387 file.into_file().into()
388 }
389 }
390 }
391}
392
393#[cfg(windows)]
394mod windows {
395 use crate::os::windows::fs::FileExt;
396 use crate::ErrorKind;
397 use std::io;
398 use std::os::windows::{
399 fs::FileExt as _,
400 io::{AsRawHandle, IntoRawHandle, RawHandle},
401 };
402
403 impl FileExt for crate::File {
404 fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
405 self.file()
406 .seek_read(buf, offset)
407 .map_err(|err| self.error(err, ErrorKind::SeekRead))
408 }
409
410 fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
411 self.file()
412 .seek_write(buf, offset)
413 .map_err(|err| self.error(err, ErrorKind::SeekWrite))
414 }
415 }
416
417 impl AsRawHandle for crate::File {
418 fn as_raw_handle(&self) -> RawHandle {
419 self.file().as_raw_handle()
420 }
421 }
422
423 impl IntoRawHandle for crate::File {
428 fn into_raw_handle(self) -> RawHandle {
429 self.file.into_raw_handle()
430 }
431 }
432
433 #[cfg(rustc_1_63)]
434 mod io_safety {
435 use std::os::windows::io::{AsHandle, BorrowedHandle, OwnedHandle};
436
437 impl AsHandle for crate::File {
438 fn as_handle(&self) -> BorrowedHandle<'_> {
439 self.file().as_handle()
440 }
441 }
442
443 impl From<crate::File> for OwnedHandle {
444 fn from(file: crate::File) -> Self {
445 file.into_parts().0.into()
446 }
447 }
448 }
449}