Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 60 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,24 +378,37 @@ impl GPTHeader {

/// A wrapper type for `String` that represents a partition's name.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PartitionName(String);
pub struct PartitionName {
string: String,
raw_buf: [u16; 36],
}

impl PartitionName {
/// Extracts a string slice containing the entire `PartitionName`.
pub fn as_str(&self) -> &str {
self.0.as_str()
&self.string
}
}

impl std::fmt::Display for PartitionName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
write!(f, "{}", &self.string)
}
}

impl From<&str> for PartitionName {
fn from(value: &str) -> PartitionName {
PartitionName(value.to_string())
let utf16_converted: Vec<_> = value
.encode_utf16()
.chain([0].into_iter().cycle())
.take(36)
.collect();
let mut raw_buf = [0; 36];
raw_buf.copy_from_slice(&utf16_converted);
PartitionName {
string: value.to_string(),
raw_buf,
}
}
}

Expand All @@ -412,18 +425,25 @@ impl<'de> Visitor<'de> for UTF16LEVisitor {
where
A: SeqAccess<'de>,
{
let mut v = Vec::new();
let mut v: Vec<u16> = Vec::new();
let mut raw_buf = [0; 36];
let mut end = false;
loop {
match seq.next_element()? {
Some(0) => end = true,
Some(x) if !end => v.push(x),
Some(_) => {}
None => break,
let mut iter = raw_buf.iter_mut();
while let Some(x) = seq.next_element()? {
if let Some(element) = iter.next() {
if x == 0 {
end = true;
}
if !end {
v.push(x);
}
*element = x;
}
}

Ok(PartitionName(String::from_utf16_lossy(&v)))
Ok(PartitionName {
string: String::from_utf16_lossy(&v),
raw_buf,
})
}
}

Expand All @@ -441,10 +461,10 @@ impl Serialize for PartitionName {
where
S: Serializer,
{
let s = self.0.encode_utf16();
// Favor using the content in the raw buffer in case there is garbage left (used for the CRC)
let mut seq = serializer.serialize_tuple(36)?;
for x in s.chain([0].iter().cycle().cloned()).take(36) {
seq.serialize_element(&x)?;
for x in self.raw_buf {
seq.serialize_element(&x.to_le_bytes())?;
}
seq.end()
}
Expand Down Expand Up @@ -1347,6 +1367,8 @@ mod test {

const DISK1: &str = "tests/fixtures/disk1.img";
const DISK2: &str = "tests/fixtures/disk2.img";
const DISK3: &str = "tests/fixtures/disk3.img";
const DISK4: &str = "tests/fixtures/disk4.img";

#[test]
fn read_header_and_partition_entries() {
Expand Down Expand Up @@ -1904,6 +1926,28 @@ mod test {
test(DISK1, 512);
test(DISK2, 4096);
}

#[test]
fn read_label_with_trailing_garbage_in_names() {
fn test(path: &str, ss: u64) {
let mut f = fs::File::open(path).unwrap();
let gpt = GPT::read_from(&mut f, ss);
// CRC check passes with trailing garbage within partition names
assert!(gpt.is_ok());
// Trailing garbage data are visible using hexdump
assert_eq!(
gpt.unwrap()
.partitions
.get(1)
.unwrap()
.partition_name
.as_str(),
"Name with garbage"
);
}
test(DISK3, 512);
test(DISK4, 4096);
}
}

#[cfg(doctest)]
Expand Down
Binary file added tests/fixtures/disk3.img
Binary file not shown.
Binary file added tests/fixtures/disk4.img
Binary file not shown.