Skip to content

Commit

Permalink
feat: Add is_read_only flag for disks across all platforms
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
kevinbaker committed Sep 12, 2024
1 parent 993f8e3 commit d0cc141
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 1 deletion.
14 changes: 14 additions & 0 deletions src/common/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/unix/apple/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(&[
Expand Down Expand Up @@ -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_,
Expand All @@ -432,6 +439,7 @@ unsafe fn new_disk(
total_space,
available_space,
is_removable,
is_read_only,
},
})
}
Expand Down
8 changes: 8 additions & 0 deletions src/unix/freebsd/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub(crate) struct DiskInner {
available_space: u64,
file_system: OsString,
is_removable: bool,
is_read_only: bool,
}

impl DiskInner {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -154,6 +159,8 @@ pub unsafe fn get_all_list(container: &mut Vec<Disk>) {

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,
Expand All @@ -163,6 +170,7 @@ pub unsafe fn get_all_list(container: &mut Vec<Disk>) {
available_space: vfs.f_favail.saturating_mul(f_frsize),
file_system: OsString::from_vec(fs_type),
is_removable,
is_read_only,
},
});
}
Expand Down
8 changes: 8 additions & 0 deletions src/unix/linux/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub(crate) struct DiskInner {
total_space: u64,
available_space: u64,
is_removable: bool,
is_read_only: bool,
}

impl DiskInner {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
Expand All @@ -128,6 +135,7 @@ fn new_disk(
total_space: cast!(total),
available_space: cast!(available),
is_removable,
is_read_only,
},
})
}
Expand Down
4 changes: 4 additions & 0 deletions src/unknown/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ impl DiskInner {
false
}

pub(crate) fn is_read_only(&self) -> bool {
false
}

pub(crate) fn refresh(&mut self) -> bool {
true
}
Expand Down
11 changes: 10 additions & 1 deletion src/windows/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -125,6 +125,7 @@ pub(crate) struct DiskInner {
total_space: u64,
available_space: u64,
is_removable: bool,
is_read_only: bool,
}

impl DiskInner {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -239,12 +244,14 @@ pub(crate) unsafe fn get_list() -> Vec<Disk> {
}
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();
Expand All @@ -255,6 +262,7 @@ pub(crate) unsafe fn get_list() -> Vec<Disk> {
);
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() {
Expand Down Expand Up @@ -324,6 +332,7 @@ pub(crate) unsafe fn get_list() -> Vec<Disk> {
total_space,
available_space,
is_removable,
is_read_only,
},
})
.collect::<Vec<_>>()
Expand Down

0 comments on commit d0cc141

Please sign in to comment.