iso9660/directory/
iterator.rs1use crate::error::{Iso9660Error, Result};
6use crate::types::{FileEntry, SECTOR_SIZE};
7use crate::directory::record::DirectoryRecord;
8use crate::utils::string;
9use gpt_disk_io::BlockIo;
10use gpt_disk_types::Lba;
11use alloc::string::String;
12use alloc::boxed::Box;
13
14pub struct DirectoryIterator<'a, B: BlockIo> {
16 block_io: &'a mut B,
17 extent_lba: u32,
18 extent_len: u32,
19 offset: usize,
20 current_sector: Box<[u8; SECTOR_SIZE]>,
21 current_sector_lba: Option<u64>,
22}
23
24impl<'a, B: BlockIo> DirectoryIterator<'a, B> {
25 pub fn new(block_io: &'a mut B, extent_lba: u32, extent_len: u32) -> Self {
27 Self {
28 block_io,
29 extent_lba,
30 extent_len,
31 offset: 0,
32 current_sector: Box::new([0u8; SECTOR_SIZE]),
33 current_sector_lba: None,
34 }
35 }
36}
37
38impl<'a, B: BlockIo> Iterator for DirectoryIterator<'a, B> {
39 type Item = Result<FileEntry>;
40
41 fn next(&mut self) -> Option<Self::Item> {
42 loop {
43 if self.offset >= self.extent_len as usize {
45 return None;
46 }
47
48 let sector_offset = self.offset / SECTOR_SIZE;
50 let lba = self.extent_lba as u64 + sector_offset as u64;
51 let offset_in_sector = self.offset % SECTOR_SIZE;
52
53 if self.current_sector_lba != Some(lba) {
55 if self.block_io.read_blocks(Lba(lba), self.current_sector.as_mut()).is_err() {
56 return Some(Err(Iso9660Error::IoError));
57 }
58 self.current_sector_lba = Some(lba);
59 }
60
61 let sector_data = &self.current_sector[offset_in_sector..];
63
64 if sector_data.is_empty() || sector_data[0] == 0 {
66 let next_sector_offset = (sector_offset + 1) * SECTOR_SIZE;
68 self.offset = next_sector_offset;
69 continue;
70 }
71
72 let record = match DirectoryRecord::parse(sector_data) {
74 Ok(r) => r,
75 Err(e) => return Some(Err(e)),
76 };
77
78 self.offset += record.length as usize;
80
81 let file_id = record.file_identifier();
83
84 let name = if file_id.len() == 1 && file_id[0] == 0 {
86 String::from(".")
87 } else if file_id.len() == 1 && file_id[0] == 1 {
88 String::from("..")
89 } else {
90 match string::dchars_to_str(file_id) {
91 Ok(s) => {
92 let stripped = string::strip_version(s);
94 String::from(stripped)
95 }
96 Err(_) => {
97 let s = String::from_utf8_lossy(file_id);
99 let stripped = string::strip_version(&s);
100 String::from(stripped)
101 }
102 }
103 };
104
105 let entry = FileEntry {
107 name,
108 size: record.get_data_length() as u64,
109 extent_lba: record.get_extent_lba(),
110 data_length: record.get_data_length(),
111 flags: record.get_flags(),
112 file_unit_size: record.file_unit_size,
113 interleave_gap: record.interleave_gap,
114 };
115
116 return Some(Ok(entry));
117 }
118 }
119}