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 #[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}