diff options
Diffstat (limited to 'vendor/sysinfo/src/linux/utils.rs')
-rw-r--r-- | vendor/sysinfo/src/linux/utils.rs | 130 |
1 files changed, 99 insertions, 31 deletions
diff --git a/vendor/sysinfo/src/linux/utils.rs b/vendor/sysinfo/src/linux/utils.rs index cd881a3d1..60a9aa2b0 100644 --- a/vendor/sysinfo/src/linux/utils.rs +++ b/vendor/sysinfo/src/linux/utils.rs @@ -2,7 +2,9 @@ use std::fs::File; use std::io::{self, Read, Seek, SeekFrom}; -use std::path::Path; +use std::path::{Path, PathBuf}; + +use crate::sys::system::REMAINING_FILES; pub(crate) fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result<String> { let mut buf = String::with_capacity(size); @@ -17,39 +19,105 @@ pub(crate) fn get_all_data<P: AsRef<Path>>(file_path: P, size: usize) -> io::Res } #[allow(clippy::useless_conversion)] -pub(crate) fn realpath(original: &Path) -> std::path::PathBuf { - use libc::{lstat, stat, S_IFLNK, S_IFMT}; - use std::fs; - use std::mem::MaybeUninit; - use std::path::PathBuf; - - fn and(x: u32, y: u32) -> u32 { - x & y - } - - // let ori = Path::new(original.to_str().unwrap()); - // Right now lstat on windows doesn't work quite well - // if cfg!(windows) { - // return PathBuf::from(ori); - // } - let result = PathBuf::from(original); - let mut result_s = result.to_str().unwrap_or("").as_bytes().to_vec(); - result_s.push(0); - let mut buf = MaybeUninit::<stat>::uninit(); - unsafe { - let res = lstat(result_s.as_ptr() as *const _, buf.as_mut_ptr()); - if res < 0 { +pub(crate) fn realpath(path: &Path) -> std::path::PathBuf { + match std::fs::read_link(path) { + Ok(f) => f, + Err(_e) => { + sysinfo_debug!("failed to get real path for {:?}: {:?}", path, _e); PathBuf::new() - } else { - let buf = buf.assume_init(); - if and(buf.st_mode.into(), S_IFMT.into()) != S_IFLNK.into() { - PathBuf::new() - } else { - match fs::read_link(&result) { - Ok(f) => f, - Err(_) => PathBuf::new(), + } + } +} + +/// Type used to correctly handle the `REMAINING_FILES` global. +pub(crate) struct FileCounter(File); + +impl FileCounter { + pub(crate) fn new(f: File) -> Option<Self> { + unsafe { + if let Ok(ref mut x) = REMAINING_FILES.lock() { + if **x > 0 { + **x -= 1; + return Some(Self(f)); } + // All file descriptors we were allowed are being used. + } + } + None + } +} + +impl std::ops::Deref for FileCounter { + type Target = File; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl std::ops::DerefMut for FileCounter { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Drop for FileCounter { + fn drop(&mut self) { + unsafe { + if let Ok(ref mut x) = crate::sys::system::REMAINING_FILES.lock() { + **x += 1; } } } } + +/// This type is used in `retrieve_all_new_process_info` because we have a "parent" path and +/// from it, we `pop`/`join` every time because it's more memory efficient than using `Path::join`. +pub(crate) struct PathHandler(PathBuf); + +impl PathHandler { + pub(crate) fn new(path: &Path) -> Self { + // `path` is the "parent" for all paths which will follow so we add a fake element at + // the end since every `PathHandler::join` call will first call `pop` internally. + Self(path.join("a")) + } +} + +pub(crate) trait PathPush { + fn join(&mut self, p: &str) -> &Path; +} + +impl PathPush for PathHandler { + fn join(&mut self, p: &str) -> &Path { + self.0.pop(); + self.0.push(p); + self.0.as_path() + } +} + +// This implementation allows to skip one allocation that is done in `PathHandler`. +impl PathPush for PathBuf { + fn join(&mut self, p: &str) -> &Path { + self.push(p); + self.as_path() + } +} + +pub(crate) fn to_u64(v: &[u8]) -> u64 { + let mut x = 0; + + for c in v { + x *= 10; + x += u64::from(c - b'0'); + } + x +} + +/// Converts a path to a NUL-terminated `Vec<u8>` suitable for use with C functions. +pub(crate) fn to_cpath(path: &std::path::Path) -> Vec<u8> { + use std::{ffi::OsStr, os::unix::ffi::OsStrExt}; + + let path_os: &OsStr = path.as_ref(); + let mut cpath = path_os.as_bytes().to_vec(); + cpath.push(0); + cpath +} |