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

google / gpt-disk-rs / 15100577344

18 May 2025 10:15PM CUT coverage: 94.803%. Remained the same
15100577344

Pull #287

github

web-flow
Merge 6095c1c95 into 8feba8cec
Pull Request #287: uguid: Fix compilation tests for guid macro

1441 of 1520 relevant lines covered (94.8%)

26.55 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> {
32✔
38
        let block_size = block_size.to_u64();
32✔
39
        let num_bytes_exact = self.num_bytes_exact()?;
32✔
40

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

46
        Some(num_blocks)
32✔
47
    }
32✔
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> {
2✔
53
        self.num_blocks(block_size)?.try_into().ok()
2✔
54
    }
2✔
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> {
54✔
66
        let entry_size = self.entry_size.to_u64();
54✔
67
        let num_entries = u64::from(self.num_entries);
54✔
68
        entry_size.checked_mul(num_entries)
54✔
69
    }
54✔
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> {
18✔
81
        self.num_bytes_exact()?.try_into().ok()
18✔
82
    }
18✔
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(
26✔
93
        &self,
26✔
94
        block_size: BlockSize,
26✔
95
    ) -> Option<u64> {
26✔
96
        let num_blocks = self.num_blocks(block_size)?;
26✔
97
        num_blocks.checked_mul(block_size.to_u64())
26✔
98
    }
26✔
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(
22✔
109
        &self,
22✔
110
        block_size: BlockSize,
22✔
111
    ) -> Option<usize> {
22✔
112
        self.num_bytes_rounded_to_block(block_size)?.try_into().ok()
22✔
113
    }
22✔
114
}
115

116
impl Display for GptPartitionEntryArrayLayout {
117
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2✔
118
        write!(
2✔
119
            f,
2✔
120
            "start_lba={}/entry_size={}/num_entries={}",
2✔
121
            self.start_lba, self.entry_size, self.num_entries
2✔
122
        )
2✔
123
    }
2✔
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
impl core::error::Error for GptPartitionEntryArrayError {}
149

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

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

173
        let num_bytes_exact = layout
16✔
174
            .num_bytes_exact_as_usize()
16✔
175
            .ok_or(GptPartitionEntryArrayError::Overflow)?;
16✔
176

177
        let storage = storage
16✔
178
            .get_mut(..num_bytes_required)
16✔
179
            .ok_or(GptPartitionEntryArrayError::BufferTooSmall)?;
16✔
180

181
        Ok(Self {
16✔
182
            layout,
16✔
183
            num_bytes_exact,
16✔
184
            storage,
16✔
185
        })
16✔
186
    }
16✔
187

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

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

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

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

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

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

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

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

245
    /// Calculate the CRC32 checksum for the partition entry array. The
246
    /// return value can then be set in the
247
    /// [`GptHeader::partition_entry_array_crc32`] field.
248
    ///
249
    /// [`GptHeader::partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
250
    #[must_use]
251
    pub fn calculate_crc32(&self) -> Crc32 {
×
252
        let crc = crc::Crc::<u32>::new(&Crc32::ALGORITHM);
×
253
        let mut digest = crc.digest();
×
254
        digest.update(&self.storage[..self.num_bytes_exact]);
×
255
        Crc32(U32Le(digest.finalize().to_le_bytes()))
×
256
    }
×
257
}
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