1use core::iter::Iterator;
4use core::str;
5
6#[allow(non_camel_case_types)]
8pub enum FileType {
9 NORMAL,
10 HLINK,
11 SYMLINK,
12 CHAR_DEV,
13 BLOCK_DEV,
14 DIR,
15 FIFO,
16 CONT,
17 EXTHDR_META,
18 EXTHDR_METANXT,
19 RESERVED(u8),
21}
22
23#[derive(Clone)]
24pub struct UstarArchiveIter<'a> {
25 pub archive: &'a [u8],
26 pub iter_curr: usize,
27}
28
29pub fn iter(archive: &[u8]) -> UstarArchiveIter<'_> {
31 UstarArchiveIter { archive, iter_curr: 0 }
32}
33
34impl<'a> Iterator for UstarArchiveIter<'a> {
35 type Item = UstarFile<'a>;
36 fn next(&mut self) -> Option<Self::Item> {
37 if self.iter_curr >= self.archive.len() {
38 return None;
39 }
40
41 let hdr = FileHdr::from_slice(&self.archive[self.iter_curr..]);
42 let hdr = hdr?;
43 if !hdr.is_ustar() {
44 return None;
45 }
46 let file_sz = hdr.size() as usize;
47 let file_start = self.iter_curr + 512;
50 let ret = Some(UstarFile {
51 hdr: hdr.clone(),
52 file: &self.archive[file_start..(file_start + file_sz)],
53 });
54 self.iter_curr += file_sz.next_multiple_of(512) + 512;
56 return ret;
57 }
58}
59
60impl FileType {
61 pub fn from_u8(flag: u8) -> Self {
62 match flag as char {
63 '0' | '\0' => Self::NORMAL,
64 '1' => Self::HLINK,
65 '2' => Self::SYMLINK,
66 '3' => Self::CHAR_DEV,
67 '5' => Self::DIR,
68 '6' => Self::FIFO,
69 '7' => Self::CONT,
70 'g' => Self::EXTHDR_META,
71 'x' => Self::EXTHDR_METANXT,
72 _ => Self::RESERVED(flag),
73 }
74 }
75}
76
77#[derive(Clone)]
84pub struct UstarFile<'a> {
85 pub hdr: FileHdr<'a>,
86 pub file: &'a [u8],
87}
88
89#[derive(Clone)]
90pub struct FileHdr<'a>(&'a [u8]);
91impl<'a> FileHdr<'a> {
92 pub fn name(&self) -> &str {
93 let file_name = to_cstr(&self.0[0..100]);
94 str::from_utf8(file_name.unwrap())
95 .unwrap()
96 .trim_matches(char::from(0))
97 }
98 pub fn owner(&self) -> &str {
99 let user_name = to_cstr(&self.0[265..265 + 32]);
100 str::from_utf8(user_name.unwrap()).unwrap()
101 }
102 pub fn owner_group(&self) -> &str {
103 let user_name = to_cstr(&self.0[297..297 + 32]);
104 str::from_utf8(user_name.unwrap()).unwrap()
105 }
106 pub fn size(&self) -> u32 {
107 let sz = &self.0[124..124 + 11];
108 oct2bin(sz)
109 }
110 pub fn is_ustar(&self) -> bool {
111 if let Ok(magic) = str::from_utf8(&self.0[257..(257 + 5)]) {
112 return magic == "ustar";
113 }
114 return false;
115 }
116 pub fn from_slice(ustar_slice: &'a [u8]) -> Option<Self> {
117 if ustar_slice.len() < 512 {
118 return None;
119 }
120 Some(Self(&ustar_slice[0..512]))
121 }
122}
123
124fn oct2bin(s: &[u8]) -> u32 {
126 let mut n: u32 = 0;
127 for u in s {
128 n *= 8;
129 let d = *u - b'0';
130 n += d as u32;
131 }
132 n
133}
134
135fn to_cstr(s: &[u8]) -> Option<&[u8]> {
137 let mut end = 0;
138 for c in s {
139 if *c == 0 {
140 if end == 0 {
141 return None;
142 } else {
143 break;
144 }
145 }
146 end += 1;
147 }
148 return Some(&s[0..=end]);
149}