1#![cfg_attr(feature = "nightly", feature(read_initializer, specialization))]
4
5extern crate time;
6#[macro_use]
7extern crate bitflags;
8extern crate nom;
9
10use std::result;
11
12pub use directory_entry::{
13 DirectoryEntry, ISODirectory, ISODirectoryIterator, ISOFile, ISOFileReader,
14};
15pub use error::ISOError;
16pub(crate) use fileref::FileRef;
17pub use fileref::ISO9660Reader;
18use parse::VolumeDescriptor;
19
20pub type Result<T> = result::Result<T, ISOError>;
21
22mod directory_entry;
23mod error;
24mod fileref;
25mod parse;
26
27pub struct ISO9660<T: ISO9660Reader> {
28 _file: FileRef<T>,
29 pub root: ISODirectory<T>,
30 primary: VolumeDescriptor,
31}
32
33macro_rules! primary_prop_str {
34 ($name:ident) => {
35 pub fn $name(&self) -> &str {
36 if let VolumeDescriptor::Primary { $name, .. } = &self.primary {
37 &$name
38 } else {
39 unreachable!()
40 }
41 }
42 };
43}
44
45impl<T: ISO9660Reader> ISO9660<T> {
46 pub fn new(mut reader: T) -> Result<ISO9660<T>> {
47 let mut buf: [u8; 2048] = [0; 2048];
48 let mut root = None;
49 let mut primary = None;
50
51 let mut lba = 16;
53
54 loop {
56 let count = reader.read_at(&mut buf, lba)?;
57
58 if count != 2048 {
59 return Err(ISOError::ReadSize(2048, count));
60 }
61
62 let descriptor = VolumeDescriptor::parse(&buf)?;
63 match &descriptor {
64 Some(VolumeDescriptor::Primary {
65 logical_block_size,
66 root_directory_entry,
67 root_directory_entry_identifier,
68 ..
69 }) => {
70 if *logical_block_size != 2048 {
71 return Err(ISOError::InvalidFs("Block size not 2048"));
75 }
76
77 root = Some((
78 root_directory_entry.clone(),
79 root_directory_entry_identifier.clone(),
80 ));
81 primary = descriptor;
82 }
83 Some(VolumeDescriptor::VolumeDescriptorSetTerminator) => break,
84 _ => {}
85 }
86
87 lba += 1;
88 }
89
90 let file = FileRef::new(reader);
91 let file2 = file.clone();
92
93 let (root, primary) = match (root, primary) {
94 (Some(root), Some(primary)) => (root, primary),
95 _ => {
96 return Err(ISOError::InvalidFs("No primary volume descriptor"));
97 }
98 };
99
100 Ok(ISO9660 {
101 _file: file,
102 root: ISODirectory::new(root.0, root.1, file2),
103 primary,
104 })
105 }
106
107 pub fn open(&self, path: &str) -> Result<Option<DirectoryEntry<T>>> {
108 let mut entry = DirectoryEntry::Directory(self.root.clone());
110 for segment in path.split('/').filter(|x| !x.is_empty()) {
111 let parent = match entry {
112 DirectoryEntry::Directory(dir) => dir,
113 _ => return Ok(None),
114 };
115
116 entry = match parent.find(segment)? {
117 Some(entry) => entry,
118 None => return Ok(None),
119 };
120 }
121
122 Ok(Some(entry))
123 }
124
125 pub fn block_size(&self) -> u16 {
126 2048 }
128
129 primary_prop_str!(volume_set_identifier);
130 primary_prop_str!(publisher_identifier);
131 primary_prop_str!(data_preparer_identifier);
132 primary_prop_str!(application_identifier);
133 primary_prop_str!(copyright_file_identifier);
134 primary_prop_str!(abstract_file_identifier);
135 primary_prop_str!(bibliographic_file_identifier);
136}