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}