From d0cc14182a5729ad58f369e0c4bff7b6d43805c4 Mon Sep 17 00:00:00 2001 From: Kevin Baker Date: Thu, 12 Sep 2024 11:26:05 -0500 Subject: [PATCH 1/4] feat: Add is_read_only flag for disks across all platforms - Implement is_read_only flag for disks on macOS, FreeBSD, Linux, and Windows - Add is_read_only() method to the common Disk struct - Update documentation for the new is_read_only() method - Ensure consistent implementation across all supported platforms This PR was written with the assistance of aider. --- src/common/disk.rs | 14 ++++++++++++++ src/unix/apple/disk.rs | 8 ++++++++ src/unix/freebsd/disk.rs | 8 ++++++++ src/unix/linux/disk.rs | 8 ++++++++ src/unknown/disk.rs | 4 ++++ src/windows/disk.rs | 11 ++++++++++- 6 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/common/disk.rs b/src/common/disk.rs index c23ee4938..9057a5c41 100644 --- a/src/common/disk.rs +++ b/src/common/disk.rs @@ -117,6 +117,20 @@ impl Disk { self.inner.is_removable() } + /// Returns `true` if the disk is read-only. + /// + /// ```no_run + /// use sysinfo::Disks; + /// + /// let disks = Disks::new_with_refreshed_list(); + /// for disk in disks.list() { + /// println!("[{:?}] is read-only: {}", disk.name(), disk.is_read_only()); + /// } + /// ``` + pub fn is_read_only(&self) -> bool { + self.inner.is_read_only() + } + /// Updates the disk' information. /// /// ```no_run diff --git a/src/unix/apple/disk.rs b/src/unix/apple/disk.rs index f16f52842..23b42a3f8 100644 --- a/src/unix/apple/disk.rs +++ b/src/unix/apple/disk.rs @@ -28,6 +28,7 @@ pub(crate) struct DiskInner { pub(crate) total_space: u64, pub(crate) available_space: u64, pub(crate) is_removable: bool, + pub(crate) is_read_only: bool, } impl DiskInner { @@ -59,6 +60,10 @@ impl DiskInner { self.is_removable } + pub(crate) fn is_read_only(&self) -> bool { + self.is_read_only + } + pub(crate) fn refresh(&mut self) -> bool { unsafe { if let Some(requested_properties) = build_requested_properties(&[ @@ -422,6 +427,8 @@ unsafe fn new_disk( ) }; + let is_read_only = (c_disk.f_flags & libc::MNT_RDONLY) != 0; + Some(Disk { inner: DiskInner { type_, @@ -432,6 +439,7 @@ unsafe fn new_disk( total_space, available_space, is_removable, + is_read_only, }, }) } diff --git a/src/unix/freebsd/disk.rs b/src/unix/freebsd/disk.rs index c65eb7b09..ab3908854 100644 --- a/src/unix/freebsd/disk.rs +++ b/src/unix/freebsd/disk.rs @@ -16,6 +16,7 @@ pub(crate) struct DiskInner { available_space: u64, file_system: OsString, is_removable: bool, + is_read_only: bool, } impl DiskInner { @@ -47,6 +48,10 @@ impl DiskInner { self.is_removable } + pub(crate) fn is_read_only(&self) -> bool { + self.is_read_only + } + pub(crate) fn refresh(&mut self) -> bool { unsafe { let mut vfs: libc::statvfs = std::mem::zeroed(); @@ -154,6 +159,8 @@ pub unsafe fn get_all_list(container: &mut Vec) { let f_frsize: u64 = vfs.f_frsize as _; + let is_read_only = (vfs.f_flag & libc::ST_RDONLY) != 0; + container.push(Disk { inner: DiskInner { name, @@ -163,6 +170,7 @@ pub unsafe fn get_all_list(container: &mut Vec) { available_space: vfs.f_favail.saturating_mul(f_frsize), file_system: OsString::from_vec(fs_type), is_removable, + is_read_only, }, }); } diff --git a/src/unix/linux/disk.rs b/src/unix/linux/disk.rs index 0df4d77bb..db96d7ac8 100644 --- a/src/unix/linux/disk.rs +++ b/src/unix/linux/disk.rs @@ -24,6 +24,7 @@ pub(crate) struct DiskInner { total_space: u64, available_space: u64, is_removable: bool, + is_read_only: bool, } impl DiskInner { @@ -55,6 +56,10 @@ impl DiskInner { self.is_removable } + pub(crate) fn is_read_only(&self) -> bool { + self.is_read_only + } + pub(crate) fn refresh(&mut self) -> bool { unsafe { let mut stat: statvfs = mem::zeroed(); @@ -103,6 +108,7 @@ fn new_disk( let type_ = find_type_for_device_name(device_name); let mut total = 0; let mut available = 0; + let mut is_read_only = false; unsafe { let mut stat: statvfs = mem::zeroed(); if retry_eintr!(statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat)) == 0 { @@ -111,6 +117,7 @@ fn new_disk( let bavail = cast!(stat.f_bavail); total = bsize.saturating_mul(blocks); available = bsize.saturating_mul(bavail); + is_read_only = (stat.f_flag & libc::ST_RDONLY) != 0; } if total == 0 { return None; @@ -128,6 +135,7 @@ fn new_disk( total_space: cast!(total), available_space: cast!(available), is_removable, + is_read_only, }, }) } diff --git a/src/unknown/disk.rs b/src/unknown/disk.rs index 9f17b5672..af2183f1f 100644 --- a/src/unknown/disk.rs +++ b/src/unknown/disk.rs @@ -35,6 +35,10 @@ impl DiskInner { false } + pub(crate) fn is_read_only(&self) -> bool { + false + } + pub(crate) fn refresh(&mut self) -> bool { true } diff --git a/src/windows/disk.rs b/src/windows/disk.rs index 16c7eafdb..a201c3fb1 100644 --- a/src/windows/disk.rs +++ b/src/windows/disk.rs @@ -12,7 +12,7 @@ use windows::core::{Error, HRESULT, PCWSTR}; use windows::Win32::Foundation::MAX_PATH; use windows::Win32::Storage::FileSystem::{ FindFirstVolumeW, FindNextVolumeW, FindVolumeClose, GetDiskFreeSpaceExW, GetDriveTypeW, - GetVolumeInformationW, GetVolumePathNamesForVolumeNameW, + GetVolumeInformationW, GetVolumePathNamesForVolumeNameW, FILE_READ_ONLY_VOLUME, }; use windows::Win32::System::Ioctl::{ PropertyStandardQuery, StorageDeviceSeekPenaltyProperty, DEVICE_SEEK_PENALTY_DESCRIPTOR, @@ -125,6 +125,7 @@ pub(crate) struct DiskInner { total_space: u64, available_space: u64, is_removable: bool, + is_read_only: bool, } impl DiskInner { @@ -156,6 +157,10 @@ impl DiskInner { self.is_removable } + pub(crate) fn is_read_only(&self) -> bool { + self.is_read_only + } + pub(crate) fn refresh(&mut self) -> bool { if self.total_space != 0 { unsafe { @@ -239,12 +244,14 @@ pub(crate) unsafe fn get_list() -> Vec { } let mut name = [0u16; MAX_PATH as usize + 1]; let mut file_system = [0u16; 32]; + let mut flags = 0; let volume_info_res = GetVolumeInformationW( raw_volume_name, Some(&mut name), None, None, None, + Some(&mut flags), Some(&mut file_system), ) .is_ok(); @@ -255,6 +262,7 @@ pub(crate) unsafe fn get_list() -> Vec { ); return Vec::new(); } + let is_read_only = (flags & FILE_READ_ONLY_VOLUME) != 0; let mount_paths = get_volume_path_names_for_volume_name(&volume_name[..]); if mount_paths.is_empty() { @@ -324,6 +332,7 @@ pub(crate) unsafe fn get_list() -> Vec { total_space, available_space, is_removable, + is_read_only, }, }) .collect::>() From 38b85e66e9fb39397abf24ee576fdae6d1492af5 Mon Sep 17 00:00:00 2001 From: Kevin Baker Date: Thu, 12 Sep 2024 13:21:19 -0500 Subject: [PATCH 2/4] cast to u32 for flag check --- src/unix/apple/disk.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/apple/disk.rs b/src/unix/apple/disk.rs index 23b42a3f8..7680b6c9d 100644 --- a/src/unix/apple/disk.rs +++ b/src/unix/apple/disk.rs @@ -427,7 +427,7 @@ unsafe fn new_disk( ) }; - let is_read_only = (c_disk.f_flags & libc::MNT_RDONLY) != 0; + let is_read_only = (c_disk.f_flags & libc::MNT_RDONLY as u32) != 0; Some(Disk { inner: DiskInner { From 1c87f50f1cc24287bbde37f2310fa20ea9c43af6 Mon Sep 17 00:00:00 2001 From: Kevin Baker Date: Thu, 12 Sep 2024 13:32:11 -0500 Subject: [PATCH 3/4] win: add correct location of FILE_READ_ONLY_VOLUME, correct call --- src/windows/disk.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/windows/disk.rs b/src/windows/disk.rs index a201c3fb1..5c880670e 100644 --- a/src/windows/disk.rs +++ b/src/windows/disk.rs @@ -12,8 +12,9 @@ use windows::core::{Error, HRESULT, PCWSTR}; use windows::Win32::Foundation::MAX_PATH; use windows::Win32::Storage::FileSystem::{ FindFirstVolumeW, FindNextVolumeW, FindVolumeClose, GetDiskFreeSpaceExW, GetDriveTypeW, - GetVolumeInformationW, GetVolumePathNamesForVolumeNameW, FILE_READ_ONLY_VOLUME, + GetVolumeInformationW, GetVolumePathNamesForVolumeNameW, }; +use windows::Win32::System::SystemServices::FILE_READ_ONLY_VOLUME; use windows::Win32::System::Ioctl::{ PropertyStandardQuery, StorageDeviceSeekPenaltyProperty, DEVICE_SEEK_PENALTY_DESCRIPTOR, IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_PROPERTY_QUERY, @@ -250,7 +251,6 @@ pub(crate) unsafe fn get_list() -> Vec { Some(&mut name), None, None, - None, Some(&mut flags), Some(&mut file_system), ) From 6d5ea97adebfdd1a036e22fc0482261a41935690 Mon Sep 17 00:00:00 2001 From: Kevin Baker Date: Thu, 12 Sep 2024 13:43:24 -0500 Subject: [PATCH 4/4] add dependency on windows SystemServices for disk --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 0f6468356..2ca8c6dd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ disk = [ "windows/Win32_Security", # For `windows::Win32::Storage::FileSystem::CreateFileW`. "windows/Win32_System_IO", "windows/Win32_System_Ioctl", + "windows/Win32_System_SystemServices", "windows/Win32_System_WindowsProgramming", ] system = [