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