1use std::{
6 ffi::{CStr, CString},
7 os::unix::io::RawFd,
8 path::Path,
9 ptr,
10};
11
12use crate::{
13 consts::{
14 BlkidFltr, BlkidFullprobeRet, BlkidProbeRet, BlkidProbreqFlags, BlkidSafeprobeRet,
15 BlkidSublksFlags, BlkidUsageFlags,
16 },
17 devno::BlkidDevno,
18 err::BlkidErr,
19 partition::BlkidPartlist,
20 topology::BlkidTopology,
21 Result,
22};
23
24pub struct BlkidProbe(pub(super) libblkid_rs_sys::blkid_probe);
26
27impl BlkidProbe {
28 pub fn new() -> Result<Self> {
30 Ok(BlkidProbe(errno_ptr!(unsafe {
31 libblkid_rs_sys::blkid_new_probe()
32 })?))
33 }
34
35 pub fn new_from_filename(filename: &Path) -> Result<Self> {
37 let filename_cstring = CString::new(filename.to_str().ok_or(BlkidErr::InvalidConv)?)?;
38 Ok(BlkidProbe(errno_ptr!(unsafe {
39 libblkid_rs_sys::blkid_new_probe_from_filename(filename_cstring.as_ptr())
40 })?))
41 }
42
43 pub fn reset(&mut self) {
45 unsafe { libblkid_rs_sys::blkid_reset_probe(self.0) }
46 }
47
48 pub fn reset_buffers(&mut self) -> Result<()> {
50 errno!(unsafe { libblkid_rs_sys::blkid_probe_reset_buffers(self.0) })
51 }
52
53 pub fn hide_range(&mut self, offset: u64, len: u64) -> Result<()> {
55 errno!(unsafe { libblkid_rs_sys::blkid_probe_hide_range(self.0, offset, len) })
56 }
57
58 pub fn set_device(
60 &mut self,
61 fd: RawFd,
62 offset: libblkid_rs_sys::blkid_loff_t,
63 size: libblkid_rs_sys::blkid_loff_t,
64 ) -> Result<()> {
65 errno!(unsafe { libblkid_rs_sys::blkid_probe_set_device(self.0, fd, offset, size) })
66 }
67
68 pub fn get_devno(&self) -> BlkidDevno {
70 BlkidDevno::new(unsafe { libblkid_rs_sys::blkid_probe_get_devno(self.0) })
71 }
72
73 pub fn get_wholedisk_devno(&self) -> BlkidDevno {
75 BlkidDevno::new(unsafe { libblkid_rs_sys::blkid_probe_get_wholedisk_devno(self.0) })
76 }
77
78 pub fn is_wholedisk(&self) -> bool {
81 (unsafe { libblkid_rs_sys::blkid_probe_is_wholedisk(self.0) }) > 0
82 }
83
84 pub fn get_size(&self) -> libblkid_rs_sys::blkid_loff_t {
86 unsafe { libblkid_rs_sys::blkid_probe_get_size(self.0) }
87 }
88
89 pub fn get_offset(&self) -> libblkid_rs_sys::blkid_loff_t {
91 unsafe { libblkid_rs_sys::blkid_probe_get_offset(self.0) }
92 }
93
94 pub fn get_sector_size(&self) -> libc::c_uint {
96 unsafe { libblkid_rs_sys::blkid_probe_get_sectorsize(self.0) }
97 }
98
99 pub fn get_fd(&self) -> Result<RawFd> {
101 errno_with_ret!(unsafe { libblkid_rs_sys::blkid_probe_get_fd(self.0) })
102 }
103
104 pub fn enable_superblocks(&mut self, enable: bool) -> Result<()> {
106 errno!(unsafe { libblkid_rs_sys::blkid_probe_enable_superblocks(self.0, enable.into()) })
107 }
108
109 pub fn set_superblock_flags(&mut self, flags: BlkidSublksFlags) -> Result<()> {
111 errno!(unsafe { libblkid_rs_sys::blkid_probe_set_superblocks_flags(self.0, flags.into()) })
112 }
113
114 pub fn reset_superblock_filter(&mut self) -> Result<()> {
116 errno!(unsafe { libblkid_rs_sys::blkid_probe_reset_superblocks_filter(self.0) })
117 }
118
119 pub fn invert_superblock_filter(&mut self) -> Result<()> {
121 errno!(unsafe { libblkid_rs_sys::blkid_probe_invert_superblocks_filter(self.0) })
122 }
123
124 pub fn filter_superblock_type(&mut self, flag: BlkidFltr, names: &[&str]) -> Result<()> {
126 let cstring_vec: Vec<_> = names.iter().map(|name| CString::new(*name)).collect();
127 if cstring_vec
128 .iter()
129 .any(|cstring_result| cstring_result.is_err())
130 {
131 return Err(BlkidErr::InvalidConv);
132 }
133 let checked_cstring_vec: Vec<_> =
134 cstring_vec.into_iter().filter_map(|cs| cs.ok()).collect();
135 let mut ptr_vec: Vec<_> = checked_cstring_vec
136 .iter()
137 .map(|cstring| cstring.as_ptr() as *mut _)
138 .collect();
139 ptr_vec.push(ptr::null_mut());
140
141 errno!(unsafe {
142 libblkid_rs_sys::blkid_probe_filter_superblocks_type(
143 self.0,
144 flag.into(),
145 ptr_vec.as_mut_ptr(),
146 )
147 })
148 }
149
150 pub fn filter_superblock_usage(
152 &mut self,
153 flag: BlkidFltr,
154 usage: BlkidUsageFlags,
155 ) -> Result<()> {
156 errno!(unsafe {
157 libblkid_rs_sys::blkid_probe_filter_superblocks_usage(self.0, flag.into(), usage.into())
158 })
159 }
160
161 pub fn enable_topology(&mut self, enable: bool) -> Result<()> {
163 errno!(unsafe { libblkid_rs_sys::blkid_probe_enable_topology(self.0, enable.into()) })
164 }
165
166 pub fn get_topology(&mut self) -> Result<BlkidTopology> {
172 Ok(BlkidTopology::new(errno_ptr!(unsafe {
173 libblkid_rs_sys::blkid_probe_get_topology(self.0)
174 })?))
175 }
176
177 pub fn enable_partitions(&mut self, enable: bool) -> Result<()> {
179 errno!(unsafe { libblkid_rs_sys::blkid_probe_enable_partitions(self.0, enable.into()) })
180 }
181
182 pub fn reset_partition_filter(&mut self) -> Result<()> {
184 errno!(unsafe { libblkid_rs_sys::blkid_probe_reset_partitions_filter(self.0) })
185 }
186
187 pub fn invert_partition_filter(&mut self) -> Result<()> {
189 errno!(unsafe { libblkid_rs_sys::blkid_probe_invert_partitions_filter(self.0) })
190 }
191
192 pub fn filter_partition_types(&mut self, flag: BlkidFltr, names: &[&str]) -> Result<()> {
197 let cstring_vec: Vec<_> = names.iter().map(|name| CString::new(*name)).collect();
198 if cstring_vec
199 .iter()
200 .any(|cstring_result| cstring_result.is_err())
201 {
202 return Err(BlkidErr::InvalidConv);
203 }
204 let checked_cstring_vec: Vec<_> =
205 cstring_vec.into_iter().filter_map(|cs| cs.ok()).collect();
206 let mut ptr_vec: Vec<_> = checked_cstring_vec
207 .iter()
208 .map(|cstring| cstring.as_ptr() as *mut _)
209 .collect();
210 ptr_vec.push(ptr::null_mut());
211
212 errno!(unsafe {
213 libblkid_rs_sys::blkid_probe_filter_partitions_type(
214 self.0,
215 flag.into(),
216 ptr_vec.as_mut_ptr(),
217 )
218 })
219 }
220
221 pub fn get_partitions(&mut self) -> Result<BlkidPartlist<'_>> {
223 Ok(BlkidPartlist::new(errno_ptr!(unsafe {
224 libblkid_rs_sys::blkid_probe_get_partitions(self.0)
225 })?))
226 }
227
228 pub fn do_probe(&mut self) -> Result<BlkidProbeRet> {
232 errno_with_ret!(unsafe { libblkid_rs_sys::blkid_do_probe(self.0) })
233 .and_then(BlkidProbeRet::try_from)
234 }
235
236 pub fn do_safeprobe(&mut self) -> Result<BlkidSafeprobeRet> {
238 let ret = unsafe { libblkid_rs_sys::blkid_do_safeprobe(self.0) };
239 if ret == -1 {
240 Err(BlkidErr::LibErr(-1))
241 } else {
242 Ok(BlkidSafeprobeRet::try_from(ret)?)
243 }
244 }
245
246 pub fn do_fullprobe(&mut self) -> Result<BlkidFullprobeRet> {
248 errno_with_ret!(unsafe { libblkid_rs_sys::blkid_do_fullprobe(self.0) })
249 .and_then(BlkidFullprobeRet::try_from)
250 }
251
252 pub fn numof_values(&self) -> Result<usize> {
254 errno_with_ret!(unsafe { libblkid_rs_sys::blkid_probe_numof_values(self.0) })
255 .map(|v| v as usize)
256 }
257
258 pub fn get_value(&self, num: libc::c_uint) -> Result<(String, String)> {
261 let num_values = self.numof_values()?;
262 if num as usize >= num_values {
263 return Err(BlkidErr::Other(format!(
264 "num must be between 0 and {}",
265 num_values - 1
266 )));
267 }
268
269 let mut name: *const libc::c_char = ptr::null();
270 let mut data: *const libc::c_char = ptr::null();
271 let mut size: usize = 0;
272 errno!(unsafe {
273 libblkid_rs_sys::blkid_probe_get_value(
274 self.0,
275 num as libc::c_int,
276 &mut name as *mut _,
277 &mut data as *mut _,
278 &mut size as *mut _,
279 )
280 })?;
281 let name = str_ptr_to_owned!(name);
282 let data = str_ptr_with_size_to_owned!(data, size);
283 Ok((name, data))
284 }
285
286 pub fn lookup_value(&self, name: &str) -> Result<String> {
288 let name_cstring = CString::new(name)?;
289
290 let mut data: *const libc::c_char = ptr::null();
291 let mut size: usize = 0;
292 errno!(unsafe {
293 libblkid_rs_sys::blkid_probe_lookup_value(
294 self.0,
295 name_cstring.as_ptr(),
296 &mut data as *mut _,
297 &mut size as *mut _,
298 )
299 })?;
300 let data = str_ptr_with_size_to_owned!(data, size);
301 Ok(data)
302 }
303
304 pub fn has_value(&self, name: &str) -> Result<bool> {
306 let name_cstring = CString::new(name)?;
307 Ok((unsafe { libblkid_rs_sys::blkid_probe_has_value(self.0, name_cstring.as_ptr()) }) != 0)
308 }
309
310 pub fn do_wipe(&mut self, dry_run: bool) -> Result<()> {
312 errno!(unsafe { libblkid_rs_sys::blkid_do_wipe(self.0, dry_run.into()) })
313 }
314
315 pub fn step_back(&mut self) -> Result<()> {
317 errno!(unsafe { libblkid_rs_sys::blkid_probe_step_back(self.0) })
318 }
319
320 pub fn set_request(&mut self, flags: BlkidProbreqFlags) -> Result<()> {
322 errno!(unsafe { libblkid_rs_sys::blkid_probe_set_request(self.0, flags.into()) })
323 }
324}
325
326impl Drop for BlkidProbe {
327 fn drop(&mut self) {
328 unsafe { libblkid_rs_sys::blkid_free_probe(self.0) }
329 }
330}
331
332pub fn is_known_fs_type(fstype: &str) -> Result<bool> {
335 let fstype_cstring = CString::new(fstype)?;
336 Ok(unsafe { libblkid_rs_sys::blkid_known_fstype(fstype_cstring.as_ptr()) } > 0)
337}
338
339pub fn get_superblock_name(
346 index: usize,
347 get_name: bool,
348 get_flags: bool,
349) -> Result<(Option<&'static str>, Option<BlkidUsageFlags>)> {
350 let mut name_ptr: *const libc::c_char = ptr::null();
351 let mut flags: libc::c_int = 0;
352 errno!(unsafe {
353 libblkid_rs_sys::blkid_superblocks_get_name(
354 index,
355 if get_name {
356 &mut name_ptr as *mut _
357 } else {
358 ptr::null_mut()
359 },
360 if get_flags {
361 &mut flags as *mut _
362 } else {
363 ptr::null_mut()
364 },
365 )
366 })?;
367 let name_option = Some(unsafe { CStr::from_ptr(name_ptr) }.to_str()?);
368 let flags_option = Some(BlkidUsageFlags::try_from(flags)?);
369 Ok((name_option, flags_option))
370}
371
372pub fn is_known_partition_type(type_: &str) -> bool {
374 let type_cstring = match CString::new(type_) {
375 Ok(s) => s,
376 Err(_) => return false,
377 };
378 (unsafe { libblkid_rs_sys::blkid_known_pttype(type_cstring.as_ptr()) }) != 0
379}
380
381pub fn get_partition_name(index: usize) -> Result<&'static str> {
388 let mut name_ptr: *const libc::c_char = ptr::null();
389 errno!(unsafe { libblkid_rs_sys::blkid_partitions_get_name(index, &mut name_ptr as *mut _) })?;
390 let name = unsafe { CStr::from_ptr(name_ptr) }.to_str()?;
391 Ok(name)
392}