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 + 511) / 512) + 1) * 512;
55 return ret;
56 }
57}
58
59impl FileType {
60 pub fn from_u8(flag: u8) -> Self {
61 match flag as char {
62 '0' | '\0' => Self::NORMAL,
63 '1' => Self::HLINK,
64 '2' => Self::SYMLINK,
65 '3' => Self::CHAR_DEV,
66 '5' => Self::DIR,
67 '6' => Self::FIFO,
68 '7' => Self::CONT,
69 'g' => Self::EXTHDR_META,
70 'x' => Self::EXTHDR_METANXT,
71 _ => Self::RESERVED(flag),
72 }
73 }
74}
75
76#[derive(Clone)]
83pub struct UstarFile<'a> {
84 pub hdr: FileHdr<'a>,
85 pub file: &'a [u8],
86}
87
88#[derive(Clone)]
89pub struct FileHdr<'a>(&'a [u8]);
90impl<'a> FileHdr<'a> {
91 pub fn name(&self) -> &str {
92 let file_name = to_cstr(&self.0[0..100]);
93 str::from_utf8(file_name.unwrap())
94 .unwrap()
95 .trim_matches(char::from(0))
96 }
97 pub fn owner(&self) -> &str {
98 let user_name = to_cstr(&self.0[265..265 + 32]);
99 str::from_utf8(user_name.unwrap()).unwrap()
100 }
101 pub fn owner_group(&self) -> &str {
102 let user_name = to_cstr(&self.0[297..297 + 32]);
103 str::from_utf8(user_name.unwrap()).unwrap()
104 }
105 pub fn size(&self) -> u32 {
106 let sz = &self.0[124..124 + 11];
107 oct2bin(sz)
108 }
109 pub fn is_ustar(&self) -> bool {
110 if let Ok(magic) = str::from_utf8(&self.0[257..(257 + 5)]) {
111 return magic == "ustar";
112 }
113 return false;
114 }
115 pub fn from_slice(ustar_slice: &'a [u8]) -> Option<Self> {
116 if ustar_slice.len() < 512 {
117 return None;
118 }
119 Some(Self(&ustar_slice[0..512]))
120 }
121}
122
123fn oct2bin(s: &[u8]) -> u32 {
125 let mut n: u32 = 0;
126 for u in s {
127 n *= 8;
128 let d = *u - b'0';
129 n += d as u32;
130 }
131 n
132}
133
134fn to_cstr(s: &[u8]) -> Option<&[u8]> {
136 let mut end = 0;
137 for c in s {
138 if *c == 0 {
139 if end == 0 {
140 return None;
141 } else {
142 break;
143 }
144 }
145 end += 1;
146 }
147 return Some(&s[0..=end]);
148}