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#[allow(unused_imports)]
13use crate as fs_err; #[derive(Debug)]
18pub struct File {
19 file: fs::File,
20 path: PathBuf,
21}
22
23pub(crate) fn open(path: &Path) -> Result<std::fs::File, impl FnOnce(PathBuf) -> io::Error> {
28 fs::File::open(path).map_err(|err| |path| Error::build(err, ErrorKind::OpenFile, path))
29}
30
31pub(crate) fn create(path: &Path) -> Result<std::fs::File, impl FnOnce(PathBuf) -> io::Error> {
33 fs::File::create(path).map_err(|err| |path| Error::build(err, ErrorKind::CreateFile, path))
34}
35
36impl File {
38 pub fn open<P>(path: P) -> Result<Self, io::Error>
42 where
43 P: Into<PathBuf>,
44 {
45 let path = path.into();
46 match open(&path) {
47 Ok(file) => Ok(File::from_parts(file, path)),
48 Err(err_gen) => Err(err_gen(path)),
49 }
50 }
51
52 pub fn create<P>(path: P) -> Result<Self, io::Error>
56 where
57 P: Into<PathBuf>,
58 {
59 let path = path.into();
60 match create(&path) {
61 Ok(file) => Ok(File::from_parts(file, path)),
62 Err(err_gen) => Err(err_gen(path)),
63 }
64 }
65
66 pub fn create_new<P>(path: P) -> Result<Self, io::Error>
70 where
71 P: Into<PathBuf>,
72 {
73 let path = path.into();
74 match fs::OpenOptions::new()
76 .read(true)
77 .write(true)
78 .create_new(true)
79 .open(&path)
80 {
81 Ok(file) => Ok(File::from_parts(file, path)),
82 Err(err) => Err(Error::build(err, ErrorKind::CreateFile, path)),
83 }
84 }
85
86 pub fn options() -> OpenOptions {
90 OpenOptions::new()
91 }
92
93 pub fn sync_all(&self) -> Result<(), io::Error> {
97 self.file
98 .sync_all()
99 .map_err(|source| self.error(source, ErrorKind::SyncFile))
100 }
101
102 pub fn sync_data(&self) -> Result<(), io::Error> {
109 self.file
110 .sync_data()
111 .map_err(|source| self.error(source, ErrorKind::SyncFile))
112 }
113
114 pub fn set_len(&self, size: u64) -> Result<(), io::Error> {
118 self.file
119 .set_len(size)
120 .map_err(|source| self.error(source, ErrorKind::SetLen))
121 }
122
123 pub fn metadata(&self) -> Result<fs::Metadata, io::Error> {
127 self.file
128 .metadata()
129 .map_err(|source| self.error(source, ErrorKind::Metadata))
130 }
131
132 pub fn try_clone(&self) -> Result<Self, io::Error> {
138 self.file
139 .try_clone()
140 .map(|file| File {
141 file,
142 path: self.path.clone(),
143 })
144 .map_err(|source| self.error(source, ErrorKind::Clone))
145 }
146
147 pub fn set_permissions(&self, perm: fs::Permissions) -> Result<(), io::Error> {
151 self.file
152 .set_permissions(perm)
153 .map_err(|source| self.error(source, ErrorKind::SetPermissions))
154 }
155}
156
157#[cfg(rustc_1_75)]
159impl File {
160 pub fn set_times(&self, times: FileTimes) -> Result<(), io::Error> {
164 self.file
165 .set_times(times)
166 .map_err(|source| self.error(source, ErrorKind::SetTimes))
167 }
168
169 pub fn set_modified(&self, time: SystemTime) -> Result<(), io::Error> {
173 self.file
174 .set_modified(time)
175 .map_err(|source| self.error(source, ErrorKind::SetModified))
176 }
177}
178
179#[cfg(rustc_1_89)]
181impl File {
182 pub fn lock(&self) -> Result<(), io::Error> {
186 self.file
187 .lock()
188 .map_err(|source| self.error(source, ErrorKind::Lock))
189 }
190
191 pub fn lock_shared(&self) -> Result<(), io::Error> {
195 self.file
196 .lock_shared()
197 .map_err(|source| self.error(source, ErrorKind::Lock))
198 }
199
200 pub fn try_lock(&self) -> Result<(), fs::TryLockError> {
204 self.file.try_lock()
205 }
206
207 pub fn try_lock_shared(&self) -> Result<(), fs::TryLockError> {
211 self.file.try_lock_shared()
212 }
213
214 pub fn unlock(&self) -> Result<(), io::Error> {
218 self.file
219 .unlock()
220 .map_err(|source| self.error(source, ErrorKind::Unlock))
221 }
222}
223
224impl File {
226 pub fn from_parts<P>(file: fs::File, path: P) -> Self
228 where
229 P: Into<PathBuf>,
230 {
231 File {
232 file,
233 path: path.into(),
234 }
235 }
236
237 pub fn into_parts(self) -> (fs::File, PathBuf) {
239 (self.file, self.path)
240 }
241
242 pub fn into_file(self) -> fs::File {
244 self.file
245 }
246
247 pub fn into_path(self) -> PathBuf {
249 self.path
250 }
251
252 pub fn file(&self) -> &fs::File {
254 &self.file
255 }
256
257 pub fn file_mut(&mut self) -> &mut fs::File {
259 &mut self.file
260 }
261
262 pub fn path(&self) -> &Path {
264 &self.path
265 }
266
267 fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error {
269 Error::build(source, kind, &self.path)
270 }
271}
272
273impl Read for File {
274 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
275 self.file
276 .read(buf)
277 .map_err(|source| self.error(source, ErrorKind::Read))
278 }
279
280 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
281 self.file
282 .read_vectored(bufs)
283 .map_err(|source| self.error(source, ErrorKind::Read))
284 }
285}
286
287impl Read for &File {
288 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
289 (&self.file)
290 .read(buf)
291 .map_err(|source| self.error(source, ErrorKind::Read))
292 }
293
294 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
295 (&self.file)
296 .read_vectored(bufs)
297 .map_err(|source| self.error(source, ErrorKind::Read))
298 }
299}
300
301impl From<File> for fs::File {
302 fn from(file: File) -> Self {
303 file.into_file()
304 }
305}
306
307impl Seek for File {
308 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
309 self.file
310 .seek(pos)
311 .map_err(|source| self.error(source, ErrorKind::Seek))
312 }
313}
314
315impl Seek for &File {
316 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
317 (&self.file)
318 .seek(pos)
319 .map_err(|source| self.error(source, ErrorKind::Seek))
320 }
321}
322
323impl Write for File {
324 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
325 self.file
326 .write(buf)
327 .map_err(|source| self.error(source, ErrorKind::Write))
328 }
329
330 fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
331 self.file
332 .write_vectored(bufs)
333 .map_err(|source| self.error(source, ErrorKind::Write))
334 }
335
336 fn flush(&mut self) -> std::io::Result<()> {
337 self.file
338 .flush()
339 .map_err(|source| self.error(source, ErrorKind::Flush))
340 }
341}
342
343impl Write for &File {
344 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
345 (&self.file)
346 .write(buf)
347 .map_err(|source| self.error(source, ErrorKind::Write))
348 }
349
350 fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
351 (&self.file)
352 .write_vectored(bufs)
353 .map_err(|source| self.error(source, ErrorKind::Write))
354 }
355
356 fn flush(&mut self) -> std::io::Result<()> {
357 (&self.file)
358 .flush()
359 .map_err(|source| self.error(source, ErrorKind::Flush))
360 }
361}
362
363#[cfg(unix)]
364mod unix {
365 use crate::os::unix::fs::FileExt;
366 use crate::ErrorKind;
367 use std::io;
368 use std::os::unix::fs::FileExt as _;
369 use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
370
371 impl AsRawFd for crate::File {
372 fn as_raw_fd(&self) -> RawFd {
373 self.file().as_raw_fd()
374 }
375 }
376
377 impl IntoRawFd for crate::File {
378 fn into_raw_fd(self) -> RawFd {
379 self.file.into_raw_fd()
380 }
381 }
382
383 impl FileExt for crate::File {
384 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
385 self.file()
386 .read_at(buf, offset)
387 .map_err(|err| self.error(err, ErrorKind::ReadAt))
388 }
389 fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
390 self.file()
391 .read_exact_at(buf, offset)
392 .map_err(|err| self.error(err, ErrorKind::ReadExactAt))
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 fn write_all_at(&self, buf: &[u8], offset: u64) -> io::Result<()> {
400 self.file()
401 .write_all_at(buf, offset)
402 .map_err(|err| self.error(err, ErrorKind::WriteAllAt))
403 }
404 }
405
406 #[cfg(rustc_1_63)]
407 mod io_safety {
408 use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
409
410 impl AsFd for crate::File {
411 fn as_fd(&self) -> BorrowedFd<'_> {
412 self.file().as_fd()
413 }
414 }
415
416 impl From<crate::File> for OwnedFd {
417 fn from(file: crate::File) -> Self {
418 file.into_file().into()
419 }
420 }
421 }
422}
423
424#[cfg(windows)]
425mod windows {
426 use crate::os::windows::fs::FileExt;
427 use crate::ErrorKind;
428 use std::io;
429 use std::os::windows::{
430 fs::FileExt as _,
431 io::{AsRawHandle, IntoRawHandle, RawHandle},
432 };
433
434 impl FileExt for crate::File {
435 fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
436 self.file()
437 .seek_read(buf, offset)
438 .map_err(|err| self.error(err, ErrorKind::SeekRead))
439 }
440
441 fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
442 self.file()
443 .seek_write(buf, offset)
444 .map_err(|err| self.error(err, ErrorKind::SeekWrite))
445 }
446 }
447
448 impl AsRawHandle for crate::File {
449 fn as_raw_handle(&self) -> RawHandle {
450 self.file().as_raw_handle()
451 }
452 }
453
454 impl IntoRawHandle for crate::File {
459 fn into_raw_handle(self) -> RawHandle {
460 self.file.into_raw_handle()
461 }
462 }
463
464 #[cfg(rustc_1_63)]
465 mod io_safety {
466 use std::os::windows::io::{AsHandle, BorrowedHandle, OwnedHandle};
467
468 impl AsHandle for crate::File {
469 fn as_handle(&self) -> BorrowedHandle<'_> {
470 self.file().as_handle()
471 }
472 }
473
474 impl From<crate::File> for OwnedHandle {
475 fn from(file: crate::File) -> Self {
476 file.into_parts().0.into()
477 }
478 }
479 }
480}