system_extensions/metadata/attribute.rs
1#[cfg(windows)]
2extern crate winapi;
3
4use std::ffi::CString;
5use std::path::Path;
6
7
8
9bitflags! {
10 /**
11 Attributes are bitwise flags that tell the system
12 what attributes to apply to a file.
13
14**Note:** Attributes are very OS specific. Each attribute will have a
15 different value depending on the OS. Some attributes might have no use
16 on certain operating systems.
17 */
18 pub struct Attributes: u32 {
19 /**
20 Represents a normal file.
21 */
22 const NORMAL = 128;
23
24 /**
25 Represents a hidden file.
26 (Windows Only. Put a '.' in front of a file on Linux.)
27 */
28 const HIDDEN = 2;
29
30 /**
31 Represents a file set to Read Only.
32 */
33 const READ_ONLY = 1;
34 }
35}
36
37/**
38 A vector of all valid attributes.
39*/
40// This exists so you can loop through attributes.
41const ATTRIBUTES: [Attributes; 3] = [Attributes::NORMAL, Attributes::HIDDEN, Attributes::READ_ONLY];
42
43/**
44 Set the attributes for a file.
45
46 This is very OS dependent and some attributes might do nothing on some operating systems.
47
48 # Params
49 file: Path -> The path to the file.<br>
50 attrib: [`Attributes`] -> The attributes to add. (Bit-wise OR can be used to set multiple attributes.)
51 # Returns
52 bool -> If the attributes were set successfully. (If not check to make sure the file path exists.)
53
54 # Example
55 ```rust
56 use std::path::Path;
57 use system_extensions::metadata::attribute::{set_attribute, Attributes};
58
59 set_attribute(Path::new("/test.txt"), Attributes::HIDDEN);
60 ```
61 Using more than one attribute:
62 ```rust
63 use std::path::Path;
64 use system_extensions::metadata::attribute::{set_attribute, Attributes};
65
66 set_attribute(Path::new("/test.txt"), Attributes::HIDDEN | Attributes::READ_ONLY);
67 ```
68*/
69#[cfg(windows)]
70pub fn set_attribute(file: &Path, attrib: Attributes) -> bool {
71 use self::winapi::um::fileapi::SetFileAttributesA;
72
73 unsafe {
74 let file_string: CString = CString::new(file.to_str().unwrap()).unwrap();
75 let success = SetFileAttributesA(file_string.as_ptr(), attrib.bits);
76
77 return success != 0;
78 }
79}
80
81/**
82 Check if a file has a certain attribute.
83
84 ## Params
85 file: &Path -> The path to the file. <br>
86 attrib: [`Attributes`] -> The attribute to check for.
87
88 ## Returns
89 If the file has the specified attribute.
90
91 ## Examples
92 ```rust
93 use std::path::Path;
94 use system_extensions::metadata::attribute::{has_attribute, Attributes};
95
96 has_attribute(Path::new("/test.txt"), Attributes::HIDDEN);
97 ```
98*/
99#[cfg(windows)]
100pub fn has_attribute(file: &Path, attrib: Attributes) -> bool {
101 use self::winapi::um::fileapi::GetFileAttributesA;
102 use self::winapi::um::fileapi::INVALID_FILE_ATTRIBUTES;
103
104 unsafe {
105 let file_string: CString = CString::new(file.to_str().unwrap()).unwrap();
106 let bits = GetFileAttributesA(file_string.as_ptr());
107
108 if bits == INVALID_FILE_ATTRIBUTES {
109 return false;
110 }
111
112 return bits & attrib.bits == attrib.bits;
113 }
114}
115
116/**
117 Get a list of attributes a file has.
118
119 ## Params
120 file: &Path -> The path to the file.
121
122 ## Returns
123 The result of a vector of the attributes.
124
125 ## Examples
126 ```rust
127 use std::path::Path;
128 use system_extensions::metadata::attribute::{get_attributes, Attributes};
129
130 attribs: Vec<Attributes> = get_attributes(Path::new("/test.txt")).unwrap();
131 ```
132*/
133#[cfg(windows)]
134pub fn get_attributes(file: &Path) -> Result<Vec<Attributes>, String> {
135 use self::winapi::um::fileapi::GetFileAttributesA;
136 use self::winapi::um::fileapi::INVALID_FILE_ATTRIBUTES;
137
138 let mut output: Vec<Attributes> = Vec::new();
139
140 unsafe {
141 let file_string: CString = CString::new(file.to_str().unwrap()).unwrap();
142 let bits = GetFileAttributesA(file_string.as_ptr());
143
144 if bits == INVALID_FILE_ATTRIBUTES {
145 return Err(String::from("Windows.h Error: Invalid file attributes. Use obtain_errors() for a detailed error."));
146 }
147
148 for att in ATTRIBUTES.iter() {
149 if bits & att.bits == att.bits {
150 output.push(*att);
151 }
152 }
153
154 return Ok(output);
155 }
156}
157
158/*
159
160 Linux Section
161
162 */
163/**
164 Set the attributes for a file.
165
166 This is very OS dependent and some attributes might do nothing on some operating systems.
167
168 # Params
169 file: Path -> The path to the file. <br>
170 attrib: [`Attributes`] -> The attributes to add. (Bit-wise OR can be used to set multiple attributes.)
171 # Returns
172 bool -> If the attributes were set successfully. (If not check to make sure the file path exists.)
173
174 # Example
175 ```rust
176 use std::path::Path;
177 use system_extensions::metadata::attribute::{set_attribute, Attributes};
178
179 set_attribute(Path::new("/test.txt"), Attributes::HIDDEN);
180 ```
181 Using more than one attribute:
182 ```rust
183 use std::path::Path;
184 use system_extensions::metadata::attribute::{set_attribute, Attributes};
185
186 set_attribute(Path::new("/test.txt"), Attributes::HIDDEN | Attributes::READ_ONLY);
187 ```
188*/
189#[cfg(unix)]
190pub fn set_attribute(path: &Path, attrib: Attributes) -> bool {
191 use std::fs;
192 use std::fs::set_permissions;
193 use std::fs::File;
194
195 let bits = attrib.bits;
196
197 if &bits & Attributes::HIDDEN.bits == Attributes::HIDDEN.bits {
198 fs::rename(path, format!(".{}", path.to_str().unwrap())).is_ok();
199 } else if &bits & Attributes::READ_ONLY.bits == Attributes::READ_ONLY.bits{
200 let result = File::create(path);
201 if result.is_err() {
202 return false;
203 }
204 let file = result.unwrap();
205 let result_meta = file.metadata();
206 if result_meta.is_err() {
207 return false;
208 }
209 let meta = result_meta.unwrap();
210 let mut perms = meta.permissions();
211 perms.set_readonly(true);
212 return set_permissions(&path, perms).is_ok();
213 }
214 true
215}
216
217/**
218 Check if a file has a certain attribute.
219
220 ## Params
221 file: &Path -> The path to the file. <br>
222 attrib: [`Attributes`] -> The attribute to check for.
223
224 ## Returns
225 If the file has the specified attribute.
226
227 ## Examples
228 ```rust
229 use std::path::Path;
230 use system_extensions::metadata::attribute::{has_attribute, Attributes};
231
232 has_attribute(Path::new("/test.txt"), Attributes::HIDDEN);
233 ```
234*/
235#[cfg(unix)]
236pub fn has_attribute(file: &Path, attrib: Attributes) -> bool {
237 use std::fs::File;
238 if attrib ==Attributes::HIDDEN {
239 let option = file.file_name();
240 if option.is_none(){
241 return false;
242 }
243 let option = option.unwrap();
244 let str = option.to_str();
245 if str.is_none(){
246 return false;
247 }
248 str.unwrap().starts_with(".")
249 } else if attrib == Attributes::READ_ONLY{
250 let result = File::open(file);
251 if result.is_err() {
252 return false;
253 }
254 let file = result.unwrap();
255 let result_meta = file.metadata();
256 if result_meta.is_err() {
257 return false;
258 }
259 let meta = result_meta.unwrap();
260 meta.permissions().readonly()
261 }else {
262 false
263 }
264}
265
266/**
267 Get a list of attributes a file has.
268
269 ## Params
270 file: &Path -> The path to the file.
271
272 ## Returns
273 The result of a vector of the attributes.
274
275 ## Examples
276 ```rust
277 use std::path::Path;
278 use system_extensions::metadata::attribute::{get_attributes, Attributes};
279
280 attribs: Vec<Attributes> = get_attributes(Path::new("/test.txt")).unwrap();
281 ```
282*/
283#[cfg(unix)]
284pub fn get_attributes(file: &Path) -> Result<Vec<Attributes>, String> {
285 let mut values: Vec<Attributes> = Vec::new();
286 if has_attribute(file, Attributes::READ_ONLY){
287 values.push(Attributes::READ_ONLY);
288 }
289 if has_attribute(file, Attributes::HIDDEN){
290 values.push(Attributes::HIDDEN);
291 }
292
293 Ok(values)
294}