1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::fs::File; |
4 | use std::io::{self, Read, Seek}; |
5 | use std::path::{Path, PathBuf}; |
6 | |
7 | use crate::sys::system::REMAINING_FILES; |
8 | |
9 | pub(crate) fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result<String> { |
10 | let mut buf: String = String::with_capacity(size); |
11 | file.rewind()?; |
12 | file.read_to_string(&mut buf)?; |
13 | Ok(buf) |
14 | } |
15 | |
16 | pub(crate) fn get_all_data<P: AsRef<Path>>(file_path: P, size: usize) -> io::Result<String> { |
17 | let mut file: File = File::open(file_path.as_ref())?; |
18 | get_all_data_from_file(&mut file, size) |
19 | } |
20 | |
21 | #[allow (clippy::useless_conversion)] |
22 | pub(crate) fn realpath(path: &Path) -> std::path::PathBuf { |
23 | match std::fs::read_link(path) { |
24 | Ok(f: PathBuf) => f, |
25 | Err(_e: Error) => { |
26 | sysinfo_debug!("failed to get real path for {:?}: {:?}" , path, _e); |
27 | PathBuf::new() |
28 | } |
29 | } |
30 | } |
31 | |
32 | /// Type used to correctly handle the `REMAINING_FILES` global. |
33 | pub(crate) struct FileCounter(File); |
34 | |
35 | impl FileCounter { |
36 | pub(crate) fn new(f: File) -> Option<Self> { |
37 | unsafe { |
38 | if let Ok(ref mut x: &mut MutexGuard<'_, isize>) = REMAINING_FILES.lock() { |
39 | if **x > 0 { |
40 | **x -= 1; |
41 | return Some(Self(f)); |
42 | } |
43 | // All file descriptors we were allowed are being used. |
44 | } |
45 | } |
46 | None |
47 | } |
48 | } |
49 | |
50 | impl std::ops::Deref for FileCounter { |
51 | type Target = File; |
52 | |
53 | fn deref(&self) -> &Self::Target { |
54 | &self.0 |
55 | } |
56 | } |
57 | impl std::ops::DerefMut for FileCounter { |
58 | fn deref_mut(&mut self) -> &mut Self::Target { |
59 | &mut self.0 |
60 | } |
61 | } |
62 | |
63 | impl Drop for FileCounter { |
64 | fn drop(&mut self) { |
65 | unsafe { |
66 | if let Ok(ref mut x: &mut MutexGuard<'_, isize>) = crate::sys::system::REMAINING_FILES.lock() { |
67 | **x += 1; |
68 | } |
69 | } |
70 | } |
71 | } |
72 | |
73 | /// This type is used in `retrieve_all_new_process_info` because we have a "parent" path and |
74 | /// from it, we `pop`/`join` every time because it's more memory efficient than using `Path::join`. |
75 | pub(crate) struct PathHandler(PathBuf); |
76 | |
77 | impl PathHandler { |
78 | pub(crate) fn new(path: &Path) -> Self { |
79 | // `path` is the "parent" for all paths which will follow so we add a fake element at |
80 | // the end since every `PathHandler::join` call will first call `pop` internally. |
81 | Self(path.join(path:"a" )) |
82 | } |
83 | } |
84 | |
85 | pub(crate) trait PathPush { |
86 | fn join(&mut self, p: &str) -> &Path; |
87 | } |
88 | |
89 | impl PathPush for PathHandler { |
90 | fn join(&mut self, p: &str) -> &Path { |
91 | self.0.pop(); |
92 | self.0.push(path:p); |
93 | self.0.as_path() |
94 | } |
95 | } |
96 | |
97 | // This implementation allows to skip one allocation that is done in `PathHandler`. |
98 | impl PathPush for PathBuf { |
99 | fn join(&mut self, p: &str) -> &Path { |
100 | self.push(path:p); |
101 | self.as_path() |
102 | } |
103 | } |
104 | |
105 | pub(crate) fn to_u64(v: &[u8]) -> u64 { |
106 | let mut x: u64 = 0; |
107 | |
108 | for c: &u8 in v { |
109 | x *= 10; |
110 | x += u64::from(c - b'0' ); |
111 | } |
112 | x |
113 | } |
114 | |
115 | /// Converts a path to a NUL-terminated `Vec<u8>` suitable for use with C functions. |
116 | pub(crate) fn to_cpath(path: &std::path::Path) -> Vec<u8> { |
117 | use std::{ffi::OsStr, os::unix::ffi::OsStrExt}; |
118 | |
119 | let path_os: &OsStr = path.as_ref(); |
120 | let mut cpath: Vec = path_os.as_bytes().to_vec(); |
121 | cpath.push(0); |
122 | cpath |
123 | } |
124 | |