morpheus_core/iso/chunk.rs
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
//! Chunk information structures
//!
//! Fixed-size structures for tracking ISO chunks across partitions.
//! All structures use fixed arrays to avoid heap allocation where possible.
/// Maximum number of chunks per ISO (16 * 4GB = 64GB max ISO size)
pub const MAX_CHUNKS: usize = 16;
/// Maximum filename length (8.3 format compatible)
pub const MAX_FILENAME_LEN: usize = 12;
/// Information about a single chunk partition
#[derive(Debug, Clone, Copy)]
pub struct ChunkInfo {
/// Partition UUID (16 bytes, from GPT)
pub partition_uuid: [u8; 16],
/// Start LBA of the partition
pub start_lba: u64,
/// End LBA of the partition
pub end_lba: u64,
/// Size of data stored in this chunk (bytes)
pub data_size: u64,
/// Chunk index (0-based)
pub index: u8,
/// Whether this chunk has been written
pub written: bool,
}
impl ChunkInfo {
/// Create an empty/uninitialized chunk info
pub const fn empty() -> Self {
Self {
partition_uuid: [0u8; 16],
start_lba: 0,
end_lba: 0,
data_size: 0,
index: 0,
written: false,
}
}
/// Check if this chunk info is valid (has a partition assigned)
pub const fn is_valid(&self) -> bool {
self.start_lba != 0 && self.end_lba > self.start_lba
}
/// Get partition size in bytes (assuming 512-byte sectors)
pub const fn partition_size(&self) -> u64 {
(self.end_lba - self.start_lba + 1) * 512
}
/// Create a new chunk info for a partition
pub const fn new(partition_uuid: [u8; 16], start_lba: u64, end_lba: u64, index: u8) -> Self {
Self {
partition_uuid,
start_lba,
end_lba,
data_size: 0,
index,
written: false,
}
}
}
/// Collection of chunks for a single ISO
#[derive(Debug, Clone)]
pub struct ChunkSet {
/// Array of chunk info (fixed size, use count for valid entries)
pub chunks: [ChunkInfo; MAX_CHUNKS],
/// Number of valid chunks in the array
pub count: usize,
/// Total ISO size in bytes
pub total_size: u64,
/// Bytes written so far (for progress tracking)
pub bytes_written: u64,
}
impl ChunkSet {
/// Create a new empty chunk set
pub const fn new() -> Self {
Self {
chunks: [ChunkInfo::empty(); MAX_CHUNKS],
count: 0,
total_size: 0,
bytes_written: 0,
}
}
/// Add a chunk to the set
///
/// Returns the chunk index on success, or None if set is full
pub fn add_chunk(&mut self, info: ChunkInfo) -> Option<usize> {
if self.count >= MAX_CHUNKS {
return None;
}
let idx = self.count;
self.chunks[idx] = info;
self.count += 1;
Some(idx)
}
/// Get a chunk by index
pub fn get(&self, index: usize) -> Option<&ChunkInfo> {
if index < self.count {
Some(&self.chunks[index])
} else {
None
}
}
/// Get a mutable chunk by index
pub fn get_mut(&mut self, index: usize) -> Option<&mut ChunkInfo> {
if index < self.count {
Some(&mut self.chunks[index])
} else {
None
}
}
/// Find chunk containing a given byte offset
pub fn chunk_for_offset(&self, offset: u64) -> Option<(usize, u64)> {
let mut cumulative = 0u64;
for i in 0..self.count {
let chunk_size = self.chunks[i].data_size;
if offset < cumulative + chunk_size {
return Some((i, offset - cumulative));
}
cumulative += chunk_size;
}
None
}
/// Calculate total capacity of all chunks
pub fn total_capacity(&self) -> u64 {
let mut total = 0u64;
for i in 0..self.count {
total += self.chunks[i].partition_size();
}
total
}
/// Check if all chunks have been written
pub fn is_complete(&self) -> bool {
if self.count == 0 {
return false;
}
for i in 0..self.count {
if !self.chunks[i].written {
return false;
}
}
true
}
/// Get write progress as percentage (0-100)
pub fn progress_percent(&self) -> u8 {
if self.total_size == 0 {
return 0;
}
((self.bytes_written * 100) / self.total_size) as u8
}
/// Iterator over valid chunks
pub fn iter(&self) -> ChunkIterator<'_> {
ChunkIterator {
chunks: &self.chunks,
count: self.count,
index: 0,
}
}
}
impl Default for ChunkSet {
fn default() -> Self {
Self::new()
}
}
/// Iterator over chunks in a ChunkSet
pub struct ChunkIterator<'a> {
chunks: &'a [ChunkInfo; MAX_CHUNKS],
count: usize,
index: usize,
}
impl<'a> Iterator for ChunkIterator<'a> {
type Item = &'a ChunkInfo;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.count {
let chunk = &self.chunks[self.index];
self.index += 1;
Some(chunk)
} else {
None
}
}
}