Skip to content

Commit e6aa732

Browse files
committed
fix: return all partitions in linux, regardless of mount status
1 parent 9705c68 commit e6aa732

File tree

1 file changed

+54
-70
lines changed

1 file changed

+54
-70
lines changed

src/unix/linux/disk.rs

+54-70
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::sys::utils::{get_all_utf8_data, to_cpath};
44
use crate::{Disk, DiskKind};
55

66
use libc::statvfs;
7+
use std::collections::HashMap;
78
use std::ffi::{OsStr, OsString};
89
use std::fs;
910
use std::mem;
@@ -78,10 +79,7 @@ impl crate::DisksInner {
7879
}
7980

8081
pub(crate) fn refresh_list(&mut self) {
81-
get_all_list(
82-
&mut self.disks,
83-
&get_all_utf8_data("/proc/mounts", 16_385).unwrap_or_default(),
84-
)
82+
get_all_list(&mut self.disks)
8583
}
8684

8785
pub(crate) fn list(&self) -> &[Disk] {
@@ -104,17 +102,17 @@ fn new_disk(
104102
let mut total = 0;
105103
let mut available = 0;
106104
unsafe {
107-
let mut stat: statvfs = mem::zeroed();
108-
if retry_eintr!(statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat)) == 0 {
109-
let bsize = cast!(stat.f_bsize);
110-
let blocks = cast!(stat.f_blocks);
111-
let bavail = cast!(stat.f_bavail);
112-
total = bsize.saturating_mul(blocks);
113-
available = bsize.saturating_mul(bavail);
114-
}
115-
if total == 0 {
116-
return None;
105+
if !mount_point.as_os_str().is_empty() {
106+
let mut stat: statvfs = mem::zeroed();
107+
if retry_eintr!(statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat)) == 0 {
108+
let bsize = cast!(stat.f_bsize);
109+
let blocks = cast!(stat.f_blocks);
110+
let bavail = cast!(stat.f_bavail);
111+
total = bsize.saturating_mul(blocks);
112+
available = bsize.saturating_mul(bavail);
113+
}
117114
}
115+
118116
let mount_point = mount_point.to_owned();
119117
let is_removable = removable_entries
120118
.iter()
@@ -204,8 +202,40 @@ fn find_type_for_device_name(device_name: &OsStr) -> DiskKind {
204202
}
205203
}
206204

207-
fn get_all_list(container: &mut Vec<Disk>, content: &str) {
205+
fn get_all_list(container: &mut Vec<Disk>) {
208206
container.clear();
207+
let partitions = get_all_utf8_data("/proc/partitions", 16_385).unwrap_or_default();
208+
let mut disks: HashMap<String, (String, String, String)> = HashMap::new();
209+
210+
for line in partitions.lines().skip(2) {
211+
let line = line.trim();
212+
let fields = line.split_whitespace();
213+
let name = format!("/dev/{}", fields.last().unwrap_or_default());
214+
disks.insert(name.clone(), (name, "".to_string(), "".to_string()));
215+
}
216+
217+
let mounts = get_all_utf8_data("/proc/mounts", 16_385).unwrap_or_default();
218+
219+
for line in mounts.lines() {
220+
let line = line.trim();
221+
let mut fields = line.split_whitespace();
222+
let fs_spec = fields.next().unwrap_or("");
223+
let fs_file = fields
224+
.next()
225+
.unwrap_or("")
226+
.replace("\\134", "\\")
227+
.replace("\\040", " ")
228+
.replace("\\011", "\t")
229+
.replace("\\012", "\n");
230+
let fs_vfstype = fields.next().unwrap_or("");
231+
if fs_spec.starts_with("/dev/") {
232+
if let Some(disk) = disks.get_mut(fs_spec) {
233+
disk.1 = fs_file.to_string();
234+
disk.2 = fs_vfstype.to_string();
235+
}
236+
}
237+
}
238+
209239
// The goal of this array is to list all removable devices (the ones whose name starts with
210240
// "usb-").
211241
let removable_entries = match fs::read_dir("/dev/disk/by-id/") {
@@ -225,61 +255,15 @@ fn get_all_list(container: &mut Vec<Disk>, content: &str) {
225255
_ => Vec::new(),
226256
};
227257

228-
for disk in content
229-
.lines()
230-
.map(|line| {
231-
let line = line.trim_start();
232-
// mounts format
233-
// http://man7.org/linux/man-pages/man5/fstab.5.html
234-
// fs_spec<tab>fs_file<tab>fs_vfstype<tab>other fields
235-
let mut fields = line.split_whitespace();
236-
let fs_spec = fields.next().unwrap_or("");
237-
let fs_file = fields
238-
.next()
239-
.unwrap_or("")
240-
.replace("\\134", "\\")
241-
.replace("\\040", " ")
242-
.replace("\\011", "\t")
243-
.replace("\\012", "\n");
244-
let fs_vfstype = fields.next().unwrap_or("");
245-
(fs_spec, fs_file, fs_vfstype)
246-
})
247-
.filter(|(fs_spec, fs_file, fs_vfstype)| {
248-
// Check if fs_vfstype is one of our 'ignored' file systems.
249-
let filtered = match *fs_vfstype {
250-
"rootfs" | // https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt
251-
"sysfs" | // pseudo file system for kernel objects
252-
"proc" | // another pseudo file system
253-
"devtmpfs" |
254-
"cgroup" |
255-
"cgroup2" |
256-
"pstore" | // https://www.kernel.org/doc/Documentation/ABI/testing/pstore
257-
"squashfs" | // squashfs is a compressed read-only file system (for snaps)
258-
"rpc_pipefs" | // The pipefs pseudo file system service
259-
"iso9660" // optical media
260-
=> true,
261-
"tmpfs" => !cfg!(feature = "linux-tmpfs"),
262-
// calling statvfs on a mounted CIFS or NFS may hang, when they are mounted with option: hard
263-
"cifs" | "nfs" | "nfs4" => !cfg!(feature = "linux-netdevs"),
264-
_ => false,
265-
};
266-
267-
!(filtered ||
268-
fs_file.starts_with("/sys") || // check if fs_file is an 'ignored' mount point
269-
fs_file.starts_with("/proc") ||
270-
(fs_file.starts_with("/run") && !fs_file.starts_with("/run/media")) ||
271-
fs_spec.starts_with("sunrpc"))
272-
})
273-
.filter_map(|(fs_spec, fs_file, fs_vfstype)| {
274-
new_disk(
275-
fs_spec.as_ref(),
276-
Path::new(&fs_file),
277-
fs_vfstype.as_ref(),
278-
&removable_entries,
279-
)
280-
})
281-
{
282-
container.push(disk);
258+
for (fs_spec, fs_file, fs_vfstype) in disks.values() {
259+
if let Some(disk) = new_disk(
260+
fs_spec.as_ref(),
261+
Path::new(&fs_file),
262+
fs_vfstype.as_ref(),
263+
&removable_entries,
264+
) {
265+
container.push(disk);
266+
}
283267
}
284268
}
285269

0 commit comments

Comments
 (0)