Skip to main content

path_extra/std/
fs.rs

1#[cfg(unix)]
2use std::os::unix::fs::PermissionsExt as _;
3use std::{
4    fs::{File, OpenOptions, Permissions},
5    io,
6    path::Path,
7};
8
9pub trait FileExt {
10    fn create_new_if_not_exists(path: impl AsRef<Path>) -> io::Result<Option<Self>>
11    where
12        Self: Sized;
13
14    fn create_if_not_exists(path: impl AsRef<Path>) -> io::Result<Option<Self>>
15    where
16        Self: Sized;
17
18    fn open_if_exists(path: impl AsRef<Path>) -> io::Result<Option<Self>>
19    where
20        Self: Sized;
21
22    fn with_permissions(&self, perm: Permissions) -> io::Result<&Self>;
23
24    fn with_permissions_readonly(&self, readonly: bool) -> io::Result<&Self>;
25
26    #[cfg(unix)]
27    fn with_permissions_mode(&self, mode: u32) -> io::Result<&Self>;
28    #[cfg(unix)]
29    fn add_permissions_mode(&self, mode: u32) -> io::Result<&Self>;
30    #[cfg(unix)]
31    fn remove_permissions_mode(&self, mode: u32) -> io::Result<&Self>;
32}
33
34impl FileExt for File {
35    #[inline]
36    fn create_new_if_not_exists(path: impl AsRef<Path>) -> io::Result<Option<Self>> {
37        match Self::create_new(path) {
38            Ok(file) => Ok(Some(file)),
39            Err(err) if err.kind() == io::ErrorKind::AlreadyExists => Ok(None),
40            Err(err) => Err(err),
41        }
42    }
43
44    #[inline]
45    fn create_if_not_exists(path: impl AsRef<Path>) -> io::Result<Option<Self>> {
46        let mut options = Self::options();
47
48        options.write(true).create_new(true);
49
50        options.open_if_not_exists(path)
51    }
52
53    #[inline]
54    fn open_if_exists(path: impl AsRef<Path>) -> io::Result<Option<Self>> {
55        match Self::open(path) {
56            Ok(file) => Ok(Some(file)),
57            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
58            Err(err) => Err(err),
59        }
60    }
61
62    #[inline]
63    fn with_permissions(&self, perm: Permissions) -> io::Result<&Self> {
64        self.set_permissions(perm)?;
65
66        Ok(self)
67    }
68
69    #[inline]
70    fn with_permissions_readonly(&self, readonly: bool) -> io::Result<&Self> {
71        let meta = self.metadata()?;
72
73        let mut perm = meta.permissions();
74
75        perm.set_readonly(readonly);
76
77        self.with_permissions(perm)
78    }
79
80    #[cfg(unix)]
81    #[inline]
82    fn with_permissions_mode(&self, mode: u32) -> io::Result<&Self> {
83        let perm = Permissions::from_mode(mode);
84
85        self.with_permissions(perm)
86    }
87
88    #[cfg(unix)]
89    #[inline]
90    fn add_permissions_mode(&self, mode: u32) -> io::Result<&Self> {
91        let meta = self.metadata()?;
92
93        let perm = meta.permissions();
94
95        self.with_permissions_mode(perm.mode() | mode)
96    }
97
98    #[cfg(unix)]
99    #[inline]
100    fn remove_permissions_mode(&self, mode: u32) -> io::Result<&Self> {
101        let meta = self.metadata()?;
102
103        let perm = meta.permissions();
104
105        self.with_permissions_mode(perm.mode() & !mode)
106    }
107}
108
109pub trait OpenOptionsExt {
110    fn open_if_not_exists(&self, path: impl AsRef<Path>) -> io::Result<Option<File>>;
111    fn open_if_exists(&self, path: impl AsRef<Path>) -> io::Result<Option<File>>;
112}
113
114impl OpenOptionsExt for OpenOptions {
115    #[inline]
116    fn open_if_not_exists(&self, path: impl AsRef<Path>) -> io::Result<Option<File>> {
117        match self.open(path) {
118            Ok(file) => Ok(Some(file)),
119            Err(err) if err.kind() == io::ErrorKind::AlreadyExists => Ok(None),
120            Err(err) => Err(err),
121        }
122    }
123
124    #[inline]
125    fn open_if_exists(&self, path: impl AsRef<Path>) -> io::Result<Option<File>> {
126        match self.open(path) {
127            Ok(file) => Ok(Some(file)),
128            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
129            Err(err) => Err(err),
130        }
131    }
132}