1use std::{
2 io,
3 path::{Path, PathBuf},
4 os::{
5 raw::c_int,
6 unix::{
7 ffi::OsStrExt,
8 fs::MetadataExt,
9 }
10 },
11};
12
13pub trait PathPermission {
14 fn access(&self, amode: c_int) -> io::Result<bool>;
16
17 fn is_readable(&self) -> io::Result<bool>;
19
20 fn is_writable(&self) -> io::Result<bool>;
22
23 fn is_excutable(&self) -> io::Result<bool>;
25
26 fn is_creatable(&self) -> io::Result<bool>;
28
29 fn is_removable(&self) -> io::Result<bool>;
31
32 fn check_access(&self, mode: u16) -> io::Result<bool>;
37
38 fn get_access(&self) -> io::Result<String>;
41
42 fn chmod(&self, mode: u16) -> io::Result<bool>;
45}
46
47impl PathPermission for Path {
48 fn access(&self, amode: c_int) -> io::Result<bool> {
49 access(self, amode)
50 }
51
52 fn is_readable(&self) -> io::Result<bool> {
53 self.access(libc::R_OK)
54 }
55
56 fn is_writable(&self) -> io::Result<bool> {
57 self.access(libc::W_OK)
58 }
59
60 fn is_excutable(&self) -> io::Result<bool> {
61 self.access(libc::X_OK)
62 }
63
64 fn is_creatable(&self) -> io::Result<bool> {
65 let parent = match self.parent() {
66 None => Path::new("./"),
69 Some(parent) => parent,
70 };
71 if ! parent.exists() {
72 parent.is_creatable()
73 } else {
74 parent.access(libc::X_OK + libc::W_OK)
77 }
78 }
79
80 fn is_removable(&self) -> io::Result<bool> {
81 if ! self.exists() {
83 return Ok(false)
84 }
85 let parent = match self.parent() {
86 None => Path::new("./"),
87 Some(parent) => parent,
88 };
89
90 if ! parent.check_access(0o1000).unwrap() {
93 parent.access(libc::X_OK + libc::W_OK)
94 } else {
95 unsafe {
97 if libc::getuid() == self.metadata().unwrap().uid() {
98 parent.access(libc::X_OK + libc::W_OK)
99 } else {
100 Ok(false)
101 }
102 }
103 }
104 }
105
106 fn check_access(&self, mode: u16) -> io::Result<bool> {
107 if let Ok(metadata) = self.metadata() {
108 if metadata.mode() as u16 & mode == mode {
109 Ok(true)
110 } else {
111 Ok(false)
112 }
113 } else {
114 Err(io::Error::last_os_error())
115 }
116 }
117
118 fn get_access(&self) -> io::Result<String> {
119 if let Ok(metadata) = self.metadata() {
120 Ok(format!("{:o}{:o}",
121 metadata.mode() as u16 & 0o7000,
122 metadata.mode() as u16 & 0o777))
123 } else {
124 Err(io::Error::last_os_error())
125 }
126 }
127
128 fn chmod(&self, mode: u16) -> io::Result<bool> {
129 chmod(self, mode)
130 }
131}
132
133impl PathPermission for PathBuf {
134 fn access(&self, amode: c_int) -> io::Result<bool> {
135 self.as_path().access(amode)
136 }
137
138 fn is_readable(&self) -> io::Result<bool> {
139 self.as_path().is_readable()
140 }
141
142 fn is_writable(&self) -> io::Result<bool> {
143 self.as_path().is_writable()
144 }
145
146 fn is_excutable(&self) -> io::Result<bool> {
147 self.as_path().is_excutable()
148 }
149
150 fn is_creatable(&self) -> io::Result<bool> {
151 self.as_path().is_creatable()
152 }
153
154 fn is_removable(&self) -> io::Result<bool> {
155 self.as_path().is_removable()
156 }
157
158 fn check_access(&self, mode: u16) -> io::Result<bool> {
159 self.as_path().check_access(mode)
160 }
161
162 fn get_access(&self) -> io::Result<String> {
163 self.as_path().get_access()
164 }
165
166 fn chmod(&self, mode: u16) -> io::Result<bool> {
167 self.as_path().chmod(mode)
168 }
169}
170
171fn access(path: &Path, mod_mask: c_int) ->io::Result<bool> {
172 let mut buf = Vec::new();
173 let buf_ptr;
174
175 buf.extend(path.as_os_str().as_bytes());
177 buf.push(0);
178
179 buf_ptr = buf.as_ptr() as *const libc::c_char;
180
181 let result = unsafe {
182 libc::access(buf_ptr, mod_mask)
183 };
184
185 match result {
186 0 => Ok(true),
187 _ => {
188 let err = io::Error::last_os_error();
189 if err.raw_os_error().unwrap() == libc::EACCES {
190 Ok(false) } else {
192 Err(err) }
194 }
195 }
196}
197
198fn chmod(path: &Path, mode: u16) -> io::Result<bool> {
199 let mut buf = Vec::new();
200 let buf_ptr;
201
202 buf.extend(path.as_os_str().as_bytes());
204 buf.push(0);
205
206 buf_ptr = buf.as_ptr() as *const libc::c_char;
207
208 let result = unsafe {
209 libc::chmod(buf_ptr, mode)
210 };
211
212 match result {
213 0 => Ok(true),
214 1 | 2 => Ok(false),
216 _ => Err(io::Error::last_os_error()),
217 }
218}