linux_file_info/
lib.rs

1use std::{process::Command, fmt::Debug, io::{Error, ErrorKind}, fs};
2use std::str::from_utf8;
3
4#[cfg(target_os = "linux")]
5#[derive(Debug)]
6pub struct LinuxEntity {
7    pub entity_name: String,
8    pub entity_type: String,
9    pub owner: String,
10    pub group: String,
11    pub hardlink: u8,
12    pub permission: u16,
13    pub size: i32,
14    pub last_change_date: String,
15}
16
17#[cfg(target_os = "linux")]
18#[derive(Debug)]
19pub struct Permissions<'a> {
20    pub entity_type: &'a str,
21    pub permission: u16
22}
23
24#[cfg(target_os = "linux")]
25fn decode_permission_string(perm_string: &str) -> Permissions {
26    let file_type = perm_string.chars().next().unwrap_or(' ');
27    let ft = match file_type {
28        '-' => "file",
29        'd' => "folder",
30        'l' => "symlink",
31        _ => panic!("Invalid file type character: {}", file_type),
32    };
33
34    let permissions = &perm_string[1..10]; 
35    let mut permission_value = 0;
36
37    for (i, chunk) in permissions.chars().collect::<Vec<char>>().chunks(3).enumerate() {
38        let mut chunk_value = 0;
39        if chunk[0] == 'r' {
40            chunk_value += 4;
41        }
42        if chunk[1] == 'w' {
43            chunk_value += 2;
44        }
45        if chunk[2] == 'x' {
46            chunk_value += 1;
47        }
48        permission_value += chunk_value * 10u16.pow(2 - i as u32);
49    }
50
51    Permissions {
52        entity_type: ft,
53        permission: permission_value,
54    }
55}
56
57#[cfg(target_os = "linux")]
58pub fn current_folder_info() -> Vec<LinuxEntity> {
59    let check_permission = Command::new("sudo").arg("ls").arg("-l").output().unwrap();
60    let mut entities: Vec<LinuxEntity> = vec![];
61    let output = from_utf8(&check_permission.stdout).unwrap();
62
63    for (index, line) in output.lines().into_iter().enumerate() {
64        if index == 0 {
65            continue;
66        }
67
68        let split_the_line: Vec<&str> = line.split_whitespace().collect();
69
70        let perm_str = decode_permission_string(split_the_line[0]);
71
72        let new_entity = LinuxEntity {
73            entity_name: split_the_line[8].to_string(),
74            entity_type: perm_str.entity_type.to_string(),
75            permission: perm_str.permission,
76            owner: split_the_line[2].to_string(),
77            group: split_the_line[3].to_string(),
78            hardlink: split_the_line[1].parse().unwrap(),
79            size: split_the_line[4].parse().unwrap(),
80            last_change_date: format!("{} {} {}", split_the_line[5], split_the_line[6], split_the_line[7])
81        };
82
83        entities.push(new_entity);
84    }
85
86    return entities;
87}
88
89#[cfg(target_os = "linux")]
90pub fn other_folder_info(path: &str) -> Result<Vec<LinuxEntity>, Error> {
91    let check_permission = Command::new("sudo").arg("ls").arg("-l").arg(path).output().unwrap();
92    let mut entities: Vec<LinuxEntity> = vec![];
93    let output = from_utf8(&check_permission.stdout).unwrap();
94
95    if !&output.starts_with("total ") {
96        return Err(Error::new(ErrorKind::InvalidInput, "Invalid input. If you want to check a file, use 'check_file()' function instead."));
97    }
98
99    for (index, line) in output.lines().into_iter().enumerate() {
100        if index == 0 {
101            continue;
102        }
103
104        let split_the_line: Vec<&str> = line.split_whitespace().collect();
105
106        let perm_str = decode_permission_string(split_the_line[0]);
107
108        let new_entity = LinuxEntity {
109            entity_name: split_the_line[8].to_string(),
110            entity_type: perm_str.entity_type.to_string(),
111            permission: perm_str.permission,
112            owner: split_the_line[2].to_string(),
113            group: split_the_line[3].to_string(),
114            hardlink: split_the_line[1].parse().unwrap(),
115            size: split_the_line[4].parse().unwrap(),
116            last_change_date: format!("{} {} {}", split_the_line[5], split_the_line[6], split_the_line[7])
117        };
118
119        entities.push(new_entity);
120    }
121
122    return Ok(entities);
123}
124
125#[cfg(target_os = "linux")]
126pub fn file_info(path: &str) -> Result<LinuxEntity, Error> {
127    let run_command = Command::new("sudo").arg("ls").arg("-l").arg(path).output().unwrap();
128    let output = from_utf8(&run_command.stdout).unwrap();
129
130    if output.starts_with("total ") {
131        return Err(Error::new(ErrorKind::InvalidInput, "Invalid input. If you want to check a folder, use 'check_other_folder()' function instead."))
132    }
133
134    let split_the_output: Vec<&str> = output.split_whitespace().collect();
135
136    let perm_str = decode_permission_string(split_the_output[0]);
137
138    let file_name;
139    
140    if split_the_output[8].contains("/") {
141        let split_the_file_name: Vec<&str> = split_the_output[8].split("/").collect();
142        
143        file_name = split_the_file_name.last().unwrap().to_string();
144    } else {
145        file_name = split_the_output[8].to_string()
146    }
147
148    Ok(LinuxEntity {
149        entity_name: file_name,
150        entity_type: perm_str.entity_type.to_string(),
151        permission: perm_str.permission,
152        owner: split_the_output[2].to_string(),
153        group: split_the_output[3].to_string(),
154        hardlink: split_the_output[1].parse().unwrap(),
155        size: split_the_output[4].parse().unwrap(),
156        last_change_date: format!("{} {} {}", split_the_output[5], split_the_output[6], split_the_output[7])
157    })
158}
159
160#[cfg(target_os = "linux")]
161pub fn is_file(path: &str) -> bool {
162    let run_command = Command::new("sudo").arg("ls").arg("-l").arg(path).output().unwrap();
163    let output = from_utf8(&run_command.stdout).unwrap();
164
165    if output.starts_with("-") {
166        return true;
167    } else {
168        return false;
169    }
170} 
171
172#[cfg(target_os = "linux")]
173pub fn is_folder(path: &str) -> bool {
174    let run_command = Command::new("sudo").arg("ls").arg("-l").arg(path).output().unwrap();
175    let output = from_utf8(&run_command.stdout).unwrap();
176
177    if output.starts_with("total ") {
178        return true;
179    } else {
180        return false;
181    }
182}
183
184#[cfg(target_os = "linux")]
185pub fn is_symlink(path: &str) -> bool {
186    let run_command = Command::new("sudo").arg("ls").arg("-l").arg(path).output().unwrap();
187    let output = from_utf8(&run_command.stdout).unwrap();
188
189    if output.starts_with("l") {
190        return true;
191    } else {
192        return false;
193    }
194}
195
196pub fn is_exist(path: &str) -> bool {
197    if fs::metadata(path).is_ok() {
198        true
199    } else {
200        false
201    }
202}
203
204
205#[cfg(target_os = "linux")]
206pub fn get_current_user() -> String {
207    let find_user_command = Command::new("whoami").output();
208
209    return match find_user_command {
210        Ok(user) => from_utf8(&user.stdout).unwrap().trim().to_string(),
211        Err(error) => {
212            eprintln!("cannot check the user because of that: {}", error);
213
214            "".to_string()
215        }
216    }
217}
218
219#[cfg(target_os = "linux")]
220pub fn find_file_return_path(file_name: &str) -> std::result::Result<Vec<String>, std::io::Error> {
221    let find_command = std::process::Command::new("find").arg("/").arg("-type").arg("f").arg("-name").arg(file_name).output();
222
223    match find_command {
224        Ok(answer) => {
225            let parse_answer = std::str::from_utf8(&answer.stdout).unwrap();
226
227            let mut files_array = vec![];
228
229            for file in parse_answer.lines() {
230                if file != "" {
231                    files_array.push(file.to_string());
232                }
233            }
234
235            
236            match files_array.len() {
237                0 => {
238            return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "there is no file has that name".to_string()));
239                },
240                _ => return Ok(files_array)
241            }
242        },
243        Err(error) => {
244            println!("{}", error);
245
246            return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "there is no file has that name".to_string()))
247        }
248    }
249}
250
251
252#[cfg(target_os = "linux")]
253pub fn find_file_in_custom_dir_and_return_path(dir: &str, file_name: &str) -> std::result::Result<Vec<String>, std::io::Error> {
254    let find_command = std::process::Command::new("find").arg(dir).arg("-type").arg("f").arg("-name").arg(file_name).output();
255
256    match find_command {
257        Ok(answer) => {
258            let parse_answer = std::str::from_utf8(&answer.stdout).unwrap();
259
260            let mut files_array = vec![];
261
262            for file in parse_answer.lines() {
263                if file != "" {
264                    files_array.push(file.to_string());
265                }
266            }
267
268            match files_array.len() {
269                0 => {
270            return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "there is no file has that name".to_string()));
271                },
272                _ => return Ok(files_array)
273            }
274        },
275        Err(error) => {
276            println!("{}", error);
277
278            return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "there is no file has that name".to_string()))
279        }
280    }
281}
282
283#[cfg(target_os = "linux")]
284pub fn find_folder_return_path(folder_name: &str) -> std::result::Result<Vec<String>, std::io::Error> {
285    let find_command = std::process::Command::new("find").arg("/").arg("-type").arg("d").arg("-name").arg(folder_name).output();
286
287    match find_command {
288        Ok(answer) => {
289            let parse_answer = std::str::from_utf8(&answer.stdout).unwrap();
290
291            let mut folders_array = vec![];
292
293            for folder in parse_answer.lines() {
294                if folder != "" {
295                    folders_array.push(folder.to_string());
296                }
297            }
298
299            
300            match folders_array.len() {
301                0 => {
302            return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "there is no folder has that name".to_string()));
303                },
304                _ => return Ok(folders_array)
305            }
306        },
307        Err(error) => {
308            println!("{}", error);
309
310            return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "there is no folder has that name".to_string()))
311        }
312    }
313}
314
315#[cfg(target_os = "linux")]
316pub fn find_folder_in_custom_dir_and_return_path(dir: &str, folder_name: &str) -> std::result::Result<Vec<String>, std::io::Error> {
317    let find_command = std::process::Command::new("find").arg(dir).arg("-type").arg("d").arg("-name").arg(folder_name).output();
318
319    match find_command {
320        Ok(answer) => {
321            let parse_answer = std::str::from_utf8(&answer.stdout).unwrap();
322
323            let mut folders_array = vec![];
324
325            for folder in parse_answer.lines() {
326                if folder != "" {
327                    folders_array.push(folder.to_string());
328                }
329            }
330
331            
332            match folders_array.len() {
333                0 => {
334            return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "there is no folder has that name".to_string()));
335                },
336                _ => return Ok(folders_array)
337            }
338        },
339        Err(error) => {
340            println!("{}", error);
341
342            return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "there is no folder has that name".to_string()))
343        }
344    }
345}
346
347
348#[cfg(target_os = "linux")]
349#[cfg(test)]
350mod tests {
351    use super::*;
352
353    #[test]
354    fn test_decode_permission_string(){
355        let perm_str = decode_permission_string("-rw-r--r--");
356
357        assert_eq!(perm_str.permission, 644 as u16);
358        assert_eq!(perm_str.entity_type, "file");
359    }
360
361    #[test]
362    fn test_current_folder_info() {
363        println!("Current Folder's Entities: {:#?}", current_folder_info())
364    }
365
366    #[test]
367    fn test_other_folder_info(){
368        println!("/sys/dev/block folder's entities: {:#?}", other_folder_info("/sys/dev/block"))
369    }
370
371    #[test]
372    fn test_file_info(){
373        println!("Check passwd file: {:#?}", file_info("/etc/passwd"))
374    }
375
376    #[test]
377    fn test_is_file(){
378        assert_eq!(true, is_file("Cargo.toml"))
379    }
380
381    #[test]
382    fn test_is_folder() {
383        assert_eq!(false, is_folder("Cargo.toml"))
384    }
385
386    // you have to do this test with finding a symlink in your computer and writing it's absolute
387    // path.
388
389    #[test]
390    fn test_is_symlink(){
391        assert_eq!(true, is_symlink("/sys/dev/block/1:0"))
392    }
393
394    #[test]
395    fn test_is_exist(){
396        assert_eq!(false, is_exist("dfsgdfsgd"))
397    }
398
399    #[test]
400    fn test_find_file_return_path(){
401        assert_eq!(true, find_file_return_path("cargo").is_ok());
402        assert_eq!(false, find_file_return_path("hdichurhfhdhdj").is_ok());
403    }
404
405
406    #[test]
407    fn test_find_folder_return_path(){
408        assert_eq!(true, find_folder_return_path("home").is_ok());
409        assert_eq!(false, find_folder_return_path("ufhfuhdh").is_ok());
410    }
411
412}