hadris_udf/descriptor/
mod.rs1mod anchor;
7mod fileset;
8mod logical;
9mod partition;
10mod primary;
11mod tag;
12
13pub use anchor::AnchorVolumeDescriptorPointer;
14pub use fileset::FileSetDescriptor;
15pub use logical::{LogicalVolumeDescriptor, Type1PartitionMap};
16pub use partition::{PartitionContents, PartitionDescriptor};
17pub use primary::PrimaryVolumeDescriptor;
18pub use tag::{DescriptorTag, TagIdentifier};
19
20use super::super::{Read, Seek, SeekFrom};
21use crate::error::{Error, Result};
22
23#[repr(C)]
31#[derive(Debug, Clone, Copy, Default, bytemuck::Zeroable, bytemuck::Pod)]
32pub struct ExtentDescriptor {
33 pub length: u32,
35 pub location: u32,
37}
38
39impl ExtentDescriptor {
40 pub fn is_empty(&self) -> bool {
42 self.length == 0
43 }
44
45 pub(crate) fn into_native(mut self) -> Self {
46 self.length = self.length.to_le();
47 self.location = self.location.to_le();
48 self
49 }
50}
51
52#[repr(C)]
62#[derive(Debug, Clone, Copy, Default)]
63pub struct LongAllocationDescriptor {
64 pub extent_length: u32,
66 pub logical_block_num: u32,
68 pub partition_ref_num: u16,
70 pub impl_use: [u8; 6],
72}
73
74unsafe impl bytemuck::Zeroable for LongAllocationDescriptor {}
75unsafe impl bytemuck::Pod for LongAllocationDescriptor {}
76
77impl LongAllocationDescriptor {
78 pub(crate) fn into_native(mut self) -> Self {
79 self.extent_length = self.extent_length.to_le();
80 self.logical_block_num = self.logical_block_num.to_le();
81 self.partition_ref_num = self.partition_ref_num.to_le();
82 self
83 }
84
85 pub fn length(&self) -> u32 {
87 self.extent_length & 0x3FFFFFFF
88 }
89
90 pub fn extent_type(&self) -> ExtentType {
92 ExtentType::from_bits((self.extent_length >> 30) as u8)
93 }
94
95 pub fn is_recorded(&self) -> bool {
97 matches!(self.extent_type(), ExtentType::RecordedAllocated)
98 }
99
100 pub fn extent_location(&self) -> LbAddr {
102 LbAddr {
103 logical_block_num: self.logical_block_num,
104 partition_ref_num: self.partition_ref_num,
105 }
106 }
107}
108
109#[repr(C)]
117#[derive(Debug, Clone, Copy, Default, bytemuck::Zeroable, bytemuck::Pod)]
118pub struct ShortAllocationDescriptor {
119 pub extent_length: u32,
121 pub extent_position: u32,
123}
124
125impl ShortAllocationDescriptor {
126 #[cfg(feature = "alloc")]
127 pub(crate) fn into_native(mut self) -> Self {
128 self.extent_length = self.extent_length.to_le();
129 self.extent_position = self.extent_position.to_le();
130 self
131 }
132
133 pub fn length(&self) -> u32 {
135 self.extent_length & 0x3FFFFFFF
136 }
137
138 pub fn extent_type(&self) -> ExtentType {
140 ExtentType::from_bits((self.extent_length >> 30) as u8)
141 }
142}
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub enum ExtentType {
147 RecordedAllocated,
149 AllocatedNotRecorded,
151 NotAllocatedNotRecorded,
153 NextExtent,
155}
156
157impl ExtentType {
158 fn from_bits(bits: u8) -> Self {
159 match bits & 0x03 {
160 0 => Self::RecordedAllocated,
161 1 => Self::AllocatedNotRecorded,
162 2 => Self::NotAllocatedNotRecorded,
163 3 => Self::NextExtent,
164 _ => unreachable!(),
165 }
166 }
167}
168
169#[repr(C)]
171#[derive(Debug, Clone, Copy, Default)]
172pub struct LbAddr {
173 pub logical_block_num: u32,
175 pub partition_ref_num: u16,
177}
178
179#[repr(C)]
187#[derive(Debug, Clone, Copy)]
188pub struct EntityIdentifier {
189 pub flags: u8,
191 pub identifier: [u8; 23],
193 pub suffix: [u8; 8],
195}
196
197impl EntityIdentifier {
198 pub const EMPTY: Self = Self {
200 flags: 0,
201 identifier: [0; 23],
202 suffix: [0; 8],
203 };
204
205 #[cfg(feature = "alloc")]
207 pub fn as_str(&self) -> alloc::string::String {
208 let end = self.identifier.iter().position(|&b| b == 0).unwrap_or(23);
209 alloc::string::String::from_utf8_lossy(&self.identifier[..end]).into_owned()
210 }
211
212 pub fn is(&self, id: &[u8]) -> bool {
214 let end = self.identifier.iter().position(|&b| b == 0).unwrap_or(23);
215 &self.identifier[..end] == id
216 }
217}
218
219impl Default for EntityIdentifier {
220 fn default() -> Self {
221 Self::EMPTY
222 }
223}
224
225unsafe impl bytemuck::Zeroable for EntityIdentifier {}
226unsafe impl bytemuck::Pod for EntityIdentifier {}
227
228#[repr(C)]
236#[derive(Debug, Clone, Copy)]
237pub struct CharSpec {
238 pub char_set_type: u8,
240 pub char_set_info: [u8; 63],
242}
243
244impl CharSpec {
245 pub const OSTA_COMPRESSED_UNICODE: Self = {
247 let mut info = [0; 63];
248 let name = b"OSTA Compressed Unicode";
249 let mut index = 0;
250 while index < name.len() {
251 info[index] = name[index];
252 index += 1;
253 }
254 Self {
255 char_set_type: 0,
256 char_set_info: info,
257 }
258 };
259}
260
261impl Default for CharSpec {
262 fn default() -> Self {
263 Self::OSTA_COMPRESSED_UNICODE
264 }
265}
266
267unsafe impl bytemuck::Zeroable for CharSpec {}
268unsafe impl bytemuck::Pod for CharSpec {}
269
270pub mod vrs {
272 pub const BEA01: &[u8; 5] = b"BEA01";
274 pub const NSR02: &[u8; 5] = b"NSR02";
276 pub const NSR03: &[u8; 5] = b"NSR03";
278 pub const TEA01: &[u8; 5] = b"TEA01";
280 pub const CD001: &[u8; 5] = b"CD001";
282}
283
284io_transform! {
285
286pub async fn parse_vrs<R: Read + Seek>(reader: &mut R) -> Result<VrsType> {
290 reader.seek(SeekFrom::Start(16 * 2048)).await?;
292
293 let mut buffer = [0u8; 2048];
294 let mut found_bea = false;
295 let mut found_nsr = None;
296
297 for _ in 0..16 {
299 reader.read_exact(&mut buffer).await?;
300
301 if buffer[0] != 0 || buffer[6] != 1 {
303 continue;
304 }
305
306 let id = &buffer[1..6];
307 match id {
308 b"BEA01" => found_bea = true,
309 b"NSR02" if found_bea => found_nsr = Some(VrsType::Nsr02),
310 b"NSR03" if found_bea => found_nsr = Some(VrsType::Nsr03),
311 b"TEA01" if found_nsr.is_some() => return Ok(found_nsr.unwrap()),
312 b"CD001" => continue, _ => continue,
314 }
315 }
316
317 match found_nsr {
318 Some(nsr) => Ok(nsr),
319 None => Err(Error::InvalidVrs),
320 }
321}
322
323} #[derive(Debug, Clone, Copy, PartialEq, Eq)]
327pub enum VrsType {
328 Nsr02,
330 Nsr03,
332}
333
334#[cfg(test)]
335mod tests {
336 use super::*;
337
338 static_assertions::const_assert_eq!(size_of::<ExtentDescriptor>(), 8);
339 static_assertions::const_assert_eq!(size_of::<LongAllocationDescriptor>(), 16);
340 static_assertions::const_assert_eq!(size_of::<ShortAllocationDescriptor>(), 8);
341 static_assertions::const_assert_eq!(size_of::<EntityIdentifier>(), 32);
342 static_assertions::const_assert_eq!(size_of::<CharSpec>(), 64);
343}