1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// Copyright (c) 2023 Nick Piaddo
// SPDX-License-Identifier: Apache-2.0 OR MIT
// From dependency library
// From standard library
use std::mem::MaybeUninit;
// From this library
use crate::ffi_utils;
use crate::probe::PartitionTable;
use crate::probe::Probe;
/// A device partition.
#[derive(Debug)]
pub struct Partition<'a> {
pub(super) ptr: libblkid::blkid_partition,
marker: &'a Probe,
}
impl<'a> Partition<'a> {
#[doc(hidden)]
/// Creates a new `Partition` instance.
pub(super) fn new(marker: &'a Probe, partition: libblkid::blkid_partition) -> Partition<'a> {
log::debug!("Partition::new creating a new `Partition` instance");
Self {
ptr: partition,
marker,
}
}
/// Returns the partition's name, if supported by the partition type (e.g. `Mac`).
pub fn name(&self) -> Option<String> {
log::debug!("Partition::name getting partition name");
let mut ptr = MaybeUninit::<*const libc::c_char>::zeroed();
unsafe {
ptr.write(libblkid::blkid_partition_get_name(self.ptr));
}
match unsafe { ptr.assume_init() } {
name_ptr if name_ptr.is_null() => {
log::debug!("Partition::name failed to get partition name. libblkid::blkid_partition_get_name returned a NULL pointer");
None
}
name_ptr => {
let name = ffi_utils::c_char_array_to_string(name_ptr);
log::debug!("Partition::name got partition name {:?}", name);
Some(name)
}
}
}
/// Returns the partition flags (or attributes for GPT partitions).
pub fn flags(&self) -> u64 {
let flags = unsafe { libblkid::blkid_partition_get_flags(self.ptr) };
log::debug!("Partition::flags partition flags: 0x{:x}", flags);
flags
}
/// Returns the partition's number (e.g. `N` in `/dev/sdN`).
///
/// Note that this number is generated by the library independently of your OS.
pub fn number(&self) -> usize {
log::debug!("Partition::number getting partition number");
let partition_number = unsafe { libblkid::blkid_partition_get_partno(self.ptr) };
log::debug!(
"Partition::number got partition number {:?}",
partition_number
);
partition_number as usize
}
/// Returns the size of a partition in sectors.
pub fn size_in_sectors(&self) -> u64 {
let size = unsafe { libblkid::blkid_partition_get_size(self.ptr) as u64 };
log::debug!(
"Partition::size_in_sectors partition size (sectors): {:?}",
size
);
size
}
/// Returns the size of a partition in bytes.
pub fn size_in_bytes(&self) -> u64 {
let size_in_sector = self.size_in_sectors();
let size = size_in_sector * 512;
log::debug!(
"Partition::size_in_bytes partition size (bytes): {:?}",
size
);
size
}
/// Returns the partition's location as an offset, in sectors, with respect
/// to the beginning of the device.
///
/// **Warning:**
/// - when scanning is limited to a **device segment**, the returned location is still
/// expressed with respect to the beginning of the whole device,
/// - for **nested partitions**, the offset can be relative to the location of the partition's
/// parent (e.g. `Solaris`), or the beginning of the entire device (e.g. `BSD`).
pub fn location_in_sectors(&self) -> u64 {
let location = unsafe { libblkid::blkid_partition_get_start(self.ptr) as u64 };
log::debug!(
"Partition::location_in_sectors partition location (sectors): {:?}",
location
);
location
}
/// Returns the partition's location as an offset, in bytes, with respect
/// to the beginning of the device.
///
/// **Warning:**
/// - when scanning is limited to a **device segment**, the returned location is still
/// expressed with respect to the beginning of the whole device,
/// - for **nested partitions**, the offset can be relative to the location of the partition's
/// parent (e.g. `Solaris`), or the beginning of the entire device (e.g. `BSD`).
pub fn location_in_bytes(&self) -> u64 {
let location_in_sectors = self.location_in_sectors();
let location = location_in_sectors * 512;
log::debug!(
"Partition::location_in_bytes partition location (bytes): {:?}",
location
);
location
}
/// Returns a partition ID intended to specify the file system the partition contains, or to
/// flag special access methods used to access these partitions (e.g. special `CHS` mappings, `LBA`
/// access, logical mapped geometries, special driver access, hidden partitions, secured or
/// encrypted file systems, etc.).
pub fn partition_type(&self) -> i32 {
let partition_type = unsafe { libblkid::blkid_partition_get_type(self.ptr) };
log::debug!(
"Partition::partition_type partition type: 0x{:x}",
partition_type
);
partition_type
}
/// Returns a Globally Unique Identifier (GUID) number, in hexadecimal, identifying a partition
/// type, when the partition is a member of a `Mac` or `EFI GPT` partition table.
pub fn partition_type_string(&self) -> Option<String> {
log::debug!("Partition::partition_type_string getting partition type");
let mut ptr = MaybeUninit::<*const libc::c_char>::zeroed();
unsafe {
ptr.write(libblkid::blkid_partition_get_type_string(self.ptr));
};
match unsafe { ptr.assume_init() } {
type_ptr if type_ptr.is_null() => {
log::debug!("Partition::partition_type_string failed to get partition type. libblkid::blkid_partition_get_type_string returned a NULL pointer");
None
}
type_ptr => {
let partition_type = ffi_utils::c_char_array_to_string(type_ptr);
log::debug!(
"Partition::partition_type_string partition type: {:?}",
partition_type
);
Some(partition_type)
}
}
}
/// Returns a partition's parent partition table.
///
/// In general, all partitions on a device share the same parent partition table. Except for
/// systems with nested partition tables, for example `BSD` or `Solaris` that use a partition
/// table inside a standard DOS Primary Partition.
pub fn partition_table(&self) -> Option<PartitionTable> {
log::debug!("Partition::partition_table getting partition's parent partition table.");
unsafe {
let mut ptr = MaybeUninit::<libblkid::blkid_parttable>::zeroed();
ptr.write(libblkid::blkid_partition_get_table(self.ptr));
match ptr.assume_init() {
table if table.is_null() => {
let err_msg = "failed to get partition's parent partition table".to_owned();
log::debug!("Partition::partition_table {}. libblkid::blkid_partition_get_table returned a NULL pointer", err_msg);
None
}
table => {
log::debug!(
"Partition::partition_table got partition's parent partition table."
);
Some(PartitionTable::new(self.marker, table))
}
}
}
}
/// Returns a partition's UUID, when the partition is a member of a `GPT` partition table.
pub fn uuid(&self) -> Option<String> {
log::debug!("Partition::uuid getting partition uuid");
let mut ptr = MaybeUninit::<*const libc::c_char>::zeroed();
unsafe {
ptr.write(libblkid::blkid_partition_get_uuid(self.ptr));
}
match unsafe { ptr.assume_init() } {
uuid_ptr if uuid_ptr.is_null() => {
log::debug!("Partition::uuid failed to get partition uuid. libblkid::blkid_partition_get_uuid returned a NULL pointer");
None
}
uuid_ptr => {
let uuid = ffi_utils::c_char_array_to_string(uuid_ptr);
log::debug!("Partition::uuid partition uuid: {:?}", uuid);
Some(uuid)
}
}
}
/// Returns `true` when the partition is an `Extended` partition.
pub fn is_extended(&self) -> bool {
let extended = unsafe { libblkid::blkid_partition_is_extended(self.ptr) == 1 };
log::debug!("Partition::is_extended {:?}", extended);
extended
}
/// Returns `true` when the partition is a `Logical` partition.
///
/// Note: this method returns `true` for all partitions in nested partition tables (e.g. `BSD disklabel`).
pub fn is_logical(&self) -> bool {
let logical = unsafe { libblkid::blkid_partition_is_logical(self.ptr) == 1 };
log::debug!("Partition::is_logical {:?}", logical);
logical
}
/// Returns `true` when the partition is a `Primary` partition.
///
/// **Note:** this method returns `false` for members of `DOS Extended Boot Record`, and all partitions
/// in nested partition tables (e.g. `BSD disklabel`).
pub fn is_primary(&self) -> bool {
let primary = unsafe { libblkid::blkid_partition_is_primary(self.ptr) == 1 };
log::debug!("Partition::is_primary {:?}", primary);
primary
}
}