• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / gpt-disk-rs / 14182859342

31 Mar 2025 10:40PM CUT coverage: 94.803%. Remained the same
14182859342

Pull #277

github

web-flow
Merge 9a5384971 into 32b4a7e87
Pull Request #277: uguid: Unconditionally use the Error trait

1441 of 1520 relevant lines covered (94.8%)

13.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.68
/gpt_disk_types/src/partition_array.rs
1
// Copyright 2022 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6
// option. This file may not be copied, modified, or distributed
7
// except according to those terms.
8

9
use crate::{BlockSize, Crc32, GptPartitionEntrySize, Lba, U32Le};
10
use core::fmt::{self, Display, Formatter};
11

12
#[cfg(feature = "bytemuck")]
13
use {
14
    crate::GptPartitionEntry,
15
    bytemuck::{from_bytes, from_bytes_mut},
16
    core::mem,
17
    core::ops::Range,
18
};
19

20
/// Disk layout of a GPT partition entry array.
21
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
22
pub struct GptPartitionEntryArrayLayout {
23
    /// First block of the array.
24
    pub start_lba: Lba,
25

26
    /// Size in bytes of each entry.
27
    pub entry_size: GptPartitionEntrySize,
28

29
    /// Number of entries in the array.
30
    pub num_entries: u32,
31
}
32

33
impl GptPartitionEntryArrayLayout {
34
    /// Get the number of blocks needed for this layout. Returns `None`
35
    /// if overflow occurs.
36
    #[must_use]
37
    pub fn num_blocks(&self, block_size: BlockSize) -> Option<u64> {
16✔
38
        let block_size = block_size.to_u64();
16✔
39
        let num_bytes_exact = self.num_bytes_exact()?;
16✔
40

41
        let mut num_blocks = num_bytes_exact / block_size;
16✔
42
        if num_bytes_exact % block_size != 0 {
16✔
43
            num_blocks = num_blocks.checked_add(1)?;
4✔
44
        }
12✔
45

46
        Some(num_blocks)
16✔
47
    }
16✔
48

49
    /// Get the number of blocks needed for this layout. Returns `None`
50
    /// if overflow occurs.
51
    #[must_use]
52
    pub fn num_blocks_as_usize(&self, block_size: BlockSize) -> Option<usize> {
1✔
53
        self.num_blocks(block_size)?.try_into().ok()
1✔
54
    }
1✔
55

56
    /// Get the number of bytes needed for the entries in this layout,
57
    /// ignoring any padding needed at the end to match the block
58
    /// size. This corresponds to the number of bytes that are covered
59
    /// by the [`partition_entry_array_crc32`].
60
    ///
61
    /// Returns `None` if overflow occurs.
62
    ///
63
    /// [`partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
64
    #[must_use]
65
    pub fn num_bytes_exact(&self) -> Option<u64> {
27✔
66
        let entry_size = self.entry_size.to_u64();
27✔
67
        let num_entries = u64::from(self.num_entries);
27✔
68
        entry_size.checked_mul(num_entries)
27✔
69
    }
27✔
70

71
    /// Get the number of bytes needed for the entries in this layout,
72
    /// ignoring any padding needed at the end to match the block
73
    /// size. This corresponds to the number of bytes that are covered
74
    /// by the [`partition_entry_array_crc32`].
75
    ///
76
    /// Returns `None` if overflow occurs.
77
    ///
78
    /// [`partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
79
    #[must_use]
80
    pub fn num_bytes_exact_as_usize(&self) -> Option<usize> {
9✔
81
        self.num_bytes_exact()?.try_into().ok()
9✔
82
    }
9✔
83

84
    /// Get the number of bytes needed for this layout, rounded up to
85
    /// the nearest block. This is equivalent to [`num_blocks`] *
86
    /// `block_size`.
87
    ///
88
    /// Returns `None` if overflow occurs.
89
    ///
90
    /// [`num_blocks`]: Self::num_blocks
91
    #[must_use]
92
    pub fn num_bytes_rounded_to_block(
13✔
93
        &self,
13✔
94
        block_size: BlockSize,
13✔
95
    ) -> Option<u64> {
13✔
96
        let num_blocks = self.num_blocks(block_size)?;
13✔
97
        num_blocks.checked_mul(block_size.to_u64())
13✔
98
    }
13✔
99

100
    /// Get the number of bytes needed for this layout, rounded up to
101
    /// the nearest block. This is equivalent to [`num_blocks`] *
102
    /// `block_size`.
103
    ///
104
    /// Returns `None` if overflow occurs.
105
    ///
106
    /// [`num_blocks`]: Self::num_blocks
107
    #[must_use]
108
    pub fn num_bytes_rounded_to_block_as_usize(
11✔
109
        &self,
11✔
110
        block_size: BlockSize,
11✔
111
    ) -> Option<usize> {
11✔
112
        self.num_bytes_rounded_to_block(block_size)?.try_into().ok()
11✔
113
    }
11✔
114
}
115

116
impl Display for GptPartitionEntryArrayLayout {
117
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1✔
118
        write!(
1✔
119
            f,
1✔
120
            "start_lba={}/entry_size={}/num_entries={}",
1✔
121
            self.start_lba, self.entry_size, self.num_entries
1✔
122
        )
1✔
123
    }
1✔
124
}
125

126
/// Errors used by [`GptPartitionEntryArray`].
127
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
128
pub enum GptPartitionEntryArrayError {
129
    /// The storage buffer is not large enough. It must be at least
130
    /// [`layout.num_bytes_rounded_to_block`] in size.
131
    ///
132
    /// [`layout.num_bytes_rounded_to_block`]: GptPartitionEntryArrayLayout::num_bytes_rounded_to_block
133
    BufferTooSmall,
134

135
    /// Numeric overflow occurred.
136
    Overflow,
137
}
138

139
impl Display for GptPartitionEntryArrayError {
140
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
×
141
        match self {
×
142
            Self::BufferTooSmall => f.write_str("storage buffer is too small"),
×
143
            Self::Overflow => f.write_str("numeric overflow occurred"),
×
144
        }
145
    }
×
146
}
147

148
/// Storage for a GPT partition entry array.
149
#[allow(missing_debug_implementations)]
150
pub struct GptPartitionEntryArray<'a> {
151
    layout: GptPartitionEntryArrayLayout,
152
    num_bytes_exact: usize,
153
    storage: &'a mut [u8],
154
}
155

156
impl<'a> GptPartitionEntryArray<'a> {
157
    /// Create a new `GptPartitionEntryArray` with the given
158
    /// `layout`. The length of `storage` must be at least
159
    /// [`layout.num_bytes_rounded_to_block`].
160
    ///
161
    /// [`layout.num_bytes_rounded_to_block`]: GptPartitionEntryArrayLayout::num_bytes_rounded_to_block
162
    pub fn new(
8✔
163
        layout: GptPartitionEntryArrayLayout,
8✔
164
        block_size: BlockSize,
8✔
165
        storage: &'a mut [u8],
8✔
166
    ) -> Result<Self, GptPartitionEntryArrayError> {
8✔
167
        let num_bytes_required = layout
8✔
168
            .num_bytes_rounded_to_block_as_usize(block_size)
8✔
169
            .ok_or(GptPartitionEntryArrayError::Overflow)?;
8✔
170

171
        let num_bytes_exact = layout
8✔
172
            .num_bytes_exact_as_usize()
8✔
173
            .ok_or(GptPartitionEntryArrayError::Overflow)?;
8✔
174

175
        let storage = storage
8✔
176
            .get_mut(..num_bytes_required)
8✔
177
            .ok_or(GptPartitionEntryArrayError::BufferTooSmall)?;
8✔
178

179
        Ok(Self {
8✔
180
            layout,
8✔
181
            num_bytes_exact,
8✔
182
            storage,
8✔
183
        })
8✔
184
    }
8✔
185

186
    /// Get a reference to the storage buffer.
187
    #[must_use]
188
    pub fn storage(&self) -> &[u8] {
4✔
189
        self.storage
4✔
190
    }
4✔
191

192
    /// Get a mutable reference to the storage buffer.
193
    #[must_use]
194
    pub fn storage_mut(&mut self) -> &mut [u8] {
6✔
195
        self.storage
6✔
196
    }
6✔
197

198
    /// Get the partition entry array layout.
199
    #[must_use]
200
    pub fn layout(&self) -> &GptPartitionEntryArrayLayout {
4✔
201
        &self.layout
4✔
202
    }
4✔
203

204
    /// Change the partition entry array's start [`Lba`].
205
    pub fn set_start_lba(&mut self, start_lba: Lba) {
2✔
206
        self.layout.start_lba = start_lba;
2✔
207
    }
2✔
208

209
    #[cfg(feature = "bytemuck")]
210
    fn get_entry_byte_range(&self, index: u32) -> Option<Range<usize>> {
14✔
211
        if index >= self.layout.num_entries {
14✔
212
            return None;
×
213
        }
14✔
214

215
        let start = usize::try_from(
14✔
216
            u64::from(index) * u64::from(self.layout.entry_size.to_u32()),
14✔
217
        )
14✔
218
        .ok()?;
14✔
219
        Some(start..start + mem::size_of::<GptPartitionEntry>())
14✔
220
    }
14✔
221

222
    /// Get a partition entry reference. The `index` is zero-based.
223
    #[cfg(feature = "bytemuck")]
224
    #[must_use]
225
    pub fn get_partition_entry(
12✔
226
        &self,
12✔
227
        index: u32,
12✔
228
    ) -> Option<&GptPartitionEntry> {
12✔
229
        Some(from_bytes(&self.storage[self.get_entry_byte_range(index)?]))
12✔
230
    }
12✔
231

232
    /// Get a mutable partition entry reference. The `index` is zero-based.
233
    #[cfg(feature = "bytemuck")]
234
    #[must_use]
235
    pub fn get_partition_entry_mut(
2✔
236
        &mut self,
2✔
237
        index: u32,
2✔
238
    ) -> Option<&mut GptPartitionEntry> {
2✔
239
        let range = self.get_entry_byte_range(index)?;
2✔
240
        Some(from_bytes_mut(&mut self.storage[range]))
2✔
241
    }
2✔
242

243
    /// Calculate the CRC32 checksum for the partition entry array. The
244
    /// return value can then be set in the
245
    /// [`GptHeader::partition_entry_array_crc32`] field.
246
    ///
247
    /// [`GptHeader::partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
248
    #[must_use]
249
    pub fn calculate_crc32(&self) -> Crc32 {
×
250
        let crc = crc::Crc::<u32>::new(&Crc32::ALGORITHM);
×
251
        let mut digest = crc.digest();
×
252
        digest.update(&self.storage[..self.num_bytes_exact]);
×
253
        Crc32(U32Le(digest.finalize().to_le_bytes()))
×
254
    }
×
255
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc