| // Take a look at the license at the top of the repository in the LICENSE file. |
| |
| #[cfg(feature = "disk")] |
| use windows::Win32::Storage::FileSystem::{ |
| CreateFileW, FILE_ACCESS_RIGHTS, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING, |
| }; |
| |
| #[cfg(any(feature = "user", feature = "system"))] |
| pub(crate) unsafe fn to_utf8_str(p: windows::core::PWSTR) -> String { |
| if p.is_null() { |
| return String::new(); |
| } |
| |
| p.to_string().unwrap_or_else(|_e| { |
| sysinfo_debug!("Failed to convert to UTF-16 string: {}", _e); |
| String::new() |
| }) |
| } |
| |
| cfg_if! { |
| if #[cfg(any(feature = "disk", feature = "system"))] { |
| use windows::Win32::Foundation::{CloseHandle, HANDLE}; |
| use std::ops::Deref; |
| |
| pub(crate) struct HandleWrapper(pub(crate) HANDLE); |
| |
| impl HandleWrapper { |
| #[cfg(feature = "system")] |
| pub(crate) fn new(handle: HANDLE) -> Option<Self> { |
| if handle.is_invalid() { |
| None |
| } else { |
| Some(Self(handle)) |
| } |
| } |
| |
| #[cfg(feature = "disk")] |
| pub(crate) unsafe fn new_from_file( |
| drive_name: &[u16], |
| open_rights: FILE_ACCESS_RIGHTS, |
| ) -> Option<Self> { |
| let lpfilename = windows::core::PCWSTR::from_raw(drive_name.as_ptr()); |
| let handle = CreateFileW( |
| lpfilename, |
| open_rights.0, |
| FILE_SHARE_READ | FILE_SHARE_WRITE, |
| None, |
| OPEN_EXISTING, |
| Default::default(), |
| Some(HANDLE::default()), |
| ) |
| .ok()?; |
| if handle.is_invalid() { |
| sysinfo_debug!( |
| "Expected handle to {:?} to be valid", |
| String::from_utf16_lossy(drive_name) |
| ); |
| None |
| } else { |
| Some(Self(handle)) |
| } |
| } |
| } |
| |
| impl Deref for HandleWrapper { |
| type Target = HANDLE; |
| |
| fn deref(&self) -> &Self::Target { |
| &self.0 |
| } |
| } |
| |
| impl Drop for HandleWrapper { |
| fn drop(&mut self) { |
| let _err = unsafe { CloseHandle(self.0) }; |
| } |
| } |
| } |
| } |
| |
| cfg_if! { |
| if #[cfg(feature = "system")] { |
| use windows::Win32::System::SystemInformation::{FIRMWARE_TABLE_PROVIDER, GetSystemFirmwareTable}; |
| use super::ffi::SMBIOSType; |
| |
| // Get the SMBIOS table using the WinAPI. |
| pub(crate) fn get_smbios_table() -> Option<Vec<u8>> { |
| const PROVIDER: FIRMWARE_TABLE_PROVIDER = FIRMWARE_TABLE_PROVIDER(u32::from_be_bytes(*b"RSMB")); |
| |
| let size = unsafe { GetSystemFirmwareTable(PROVIDER, 0, None) }; |
| if size == 0 { |
| return None; |
| } |
| |
| let mut buffer = vec![0u8; size as usize]; |
| |
| let res = unsafe { GetSystemFirmwareTable(PROVIDER, 0, Some(&mut buffer)) }; |
| if res == 0 { |
| return None; |
| } |
| |
| Some(buffer) |
| } |
| |
| // Parses the SMBIOS table to get mainboard information (type number). |
| // Returns a part of struct with its associated strings. |
| // The parsing format is described here: https://wiki.osdev.org/System_Management_BIOS |
| // and here: https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.6.0.pdf |
| pub(crate) fn parse_smbios<T: SMBIOSType>(table: &[u8], number: u8) -> Option<(T, Vec<&str>)> { |
| // Skip SMBIOS types until type `number` is reached. |
| // All indexes provided by the structure start at 1. |
| // If the index is 0, the value has not been filled in. |
| // At index i: |
| // table[i] is the current SMBIOS type. |
| // table[i + 1] is the length of the current SMBIOS table header |
| // Strings section starts immediately after the SMBIOS header, |
| // and is a list of null-terminated strings, terminated with two \0. |
| let mut i = 0; |
| while i + 1 < table.len() { |
| if table[i] == number { |
| break; |
| } |
| i += table[i + 1] as usize; |
| // Skip strings table (terminated itself by \0) |
| while i < table.len() { |
| if table[i] == 0 && table[i + 1] == 0 { |
| i += 2; |
| break; |
| } |
| i += 1; |
| } |
| } |
| |
| let info: T = unsafe { std::ptr::read_unaligned(table[i..].as_ptr() as *const _) }; |
| |
| // As said in the SMBIOS 3 standard: https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.6.0.pdf, |
| // the strings are necessarily in UTF-8. |
| let values = table[(i + info.length() as usize)..] |
| .split(|&b| b == 0) |
| .map(|s| unsafe { std::str::from_utf8_unchecked(s) }) |
| .take_while(|s| !s.is_empty()) |
| .collect(); |
| |
| Some((info, values)) |
| } |
| } |
| } |