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
// https://people.freebsd.org/~emaste/rrip112.pdf
pub enum Entity<'data> {
Name {
name: &'data str,
},
PosixAttributes {
posix_file_mode: u32,
posix_file_links: u32,
posix_file_user_id: u32,
posix_file_group_id: u32,
posix_file_serial_number: u32,
},
}
pub struct RockRidgeParser<'data> {
data: &'data [u8],
index: usize
}
impl<'data> RockRidgeParser<'data> {
pub fn new(data: &'data [u8]) -> Self {
Self {
data,
index: 0,
}
}
}
impl<'data> Iterator for RockRidgeParser<'data> {
type Item = Entity<'data>;
fn next(&mut self) -> Option<Self::Item> {
if self.index + 2 < self.data.len() {
let identifier = &self.data[self.index..=self.index + 1];
let length = self.data[self.index + 2] as usize;
// println!("ID: {:x?}; Len: {}", identifier, length);
match identifier {
b"SP" => {
// IDK what `SP` is and there's no definition in the Rock Ridge spec, so skip this entity.
self.index += 7;
return self.next();
}
b"PX" => {
// WTF???
// Extract data
// let system_use_entry_version = data[index + 4];
let posix_file_mode = &self.data[self.index + 5..=self.index + 12];
let posix_file_links = &self.data[self.index + 13..=self.index + 20];
let posix_file_user_id = &self.data[self.index + 21..=self.index + 28];
let posix_file_group_id = &self.data[self.index + 29..=self.index + 36];
let posix_file_serial_number = &self.data[self.index + 37..=self.index + 44];
// First 4 bytes are needed, because each entry here is a (LSB-MSB) pair.
let posix_file_mode: u32 =
u32::from_le_bytes(posix_file_mode[..4].try_into().unwrap());
let posix_file_links: u32 =
u32::from_le_bytes(posix_file_links[..4].try_into().unwrap());
let posix_file_user_id: u32 =
u32::from_le_bytes(posix_file_user_id[..4].try_into().unwrap());
let posix_file_group_id: u32 =
u32::from_le_bytes(posix_file_group_id[..4].try_into().unwrap());
let posix_file_serial_number: u32 =
u32::from_le_bytes(posix_file_serial_number[..4].try_into().unwrap());
self.index += length;
return Some(Entity::PosixAttributes {
posix_file_mode,
posix_file_links,
posix_file_user_id,
posix_file_group_id,
posix_file_serial_number,
});
}
b"TF" => {
// let system_use_entry_version = data[index + 4];
// let flags = data[index + 5];
self.index += length;
return self.next();
}
b"CE" => {
// Just skip it
self.index += length;
return self.next();
}
b"AL" => {
// Do I know what the hell is this?
self.index += length;
return self.next();
}
b"NM" => {
// let system_use_entry_version = data[index + 4];
let flags = self.data[self.index + 4];
if (flags & (1 << 1)) != 0 {
self.index += length;
return Some(Entity::Name { name: "." });
}
if (flags & (1 << 2)) != 0 {
self.index += length;
return Some(Entity::Name { name: ".." });
}
let start = self.index + 5;
let end = self.index + length;
let name = &self.data[start..end];
self.index += length;
return Some(Entity::Name {
name: str::from_utf8(name).unwrap(),
});
}
&_ => {
todo!(
"Implement entity: {} ({}, {})",
str::from_utf8(identifier).unwrap(),
self.data[self.index],
self.data[self.index + 1]
);
}
}
} else {
None
}
}
}
#[inline(always)]
pub fn parse<'data>(data: &'data [u8]) -> RockRidgeParser<'data> {
RockRidgeParser::new(data)
}