1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 //! header
16 
17 #[allow(unused)]
18 use crate::utils::hdc_log::*;
19 use core::fmt;
20 use std::fmt::Debug;
21 
22 /// header len
23 pub const HEADER_LEN: u64 = 512;
24 const SUM_CONSTANT: u32 = 256;
25 
26 /// file type
27 #[repr(u8)]
28 #[derive(Debug, PartialEq, Clone, Copy)]
29 pub enum TypeFlage {
30     /// 无效值
31     Invalid = 0u8,
32     /// 0: 普通文件
33     OrdinaryFile = 48u8,
34     /// 1: 硬链接
35     HardLink = 49u8,
36     /// 2: 软链接
37     SoftLink = 50u8,
38     /// 3: 字符设备
39     CharacterDevice = 51u8,
40     /// 4: 块设备
41     BlockDevice = 52u8,
42     /// 5: 文件夹
43     Directory = 53u8,
44     /// 6: 命名管道
45     Fifo = 54u8,
46     /// 7: 保留字
47     Reserve = 55u8,
48 }
49 
50 impl TryFrom<u8> for TypeFlage {
51     type Error = ();
try_fromnull52     fn try_from(value: u8) -> Result<Self, Self::Error> {
53         match value {
54             0u8 => Ok(Self::Invalid),
55             48u8 => Ok(Self::OrdinaryFile),
56             49u8 => Ok(Self::HardLink),
57             50u8 => Ok(Self::SoftLink),
58             51u8 => Ok(Self::CharacterDevice),
59             52u8 => Ok(Self::BlockDevice),
60             53u8 => Ok(Self::Directory),
61             54u8 => Ok(Self::Fifo),
62             55u8 => Ok(Self::Reserve),
63             _ => Ok(Self::Invalid),
64         }
65     }
66 }
67 
68 /// entry header
69 pub struct Header {
70     /// 存储文件路径。tar只有100位,不够的使用prefix进行拼接
71     name: [u8; 100],
72     /// 存储文件权限
73     mode: [u8; 8],
74     /// 用户ID。和tar格式保持一致。暂不使用,预留字段
75     uid: [u8; 8],
76     /// 组ID。和uid一样,预留
77     gid: [u8; 8],
78     /// 文件大小。以8进制进行存储
79     /// 如果是目录,则填充11个0:00000000000+NUL
80     /// 如果是文件,则取出文件的字节大小,假设文件大小为;1024byte,转换到8进制字符串为:2000,不足前面补0: 00000002000+NUL
81     size: [u8; 12],
82     /// 文件最后修改时间,10位时间戳的8进制字符。UTC时间。暂不使用
83     mtime: [u8; 12],
84     /// 完整性校验。暂不使用
85     chksum: [u8; 8],
86     /// 文件类型
87     typeflage: [u8; 1],
88     /// 链接名。暂不使用
89     linkname: [u8; 100],
90     /// TAR数据段标识字段。不需要填00000+NUL,否则填写:ustar+NUL,表示是TAR文件数据
91     magic: [u8; 6],
92     /// 表示TAR文件结构的版本号
93     version: [u8; 2],
94     /// 计算机用户名。暂不使用
95     uname: [u8; 32],
96     /// 用户组名。暂不使用
97     gname: [u8; 32],
98     /// 主设备号,暂不使用
99     devmajor: [u8; 8],
100     /// 次设备号,暂不使用
101     devminor: [u8; 8],
102     /// 文件路径前缀
103     prefix: [u8; 155],
104     pad: [u8; 12],
105 }
106 
107 impl std::fmt::Debug for Header {
fmtnull108     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109         writeln!(f, "name : {}\n", self.name())
110     }
111 }
112 
113 impl Default for Header {
114     fn default() -> Self {
115         Self::new()
116     }
117 }
118 
119 /// ustar
120 const MAGIC: [u8; 6] = [b'u', b's', b't', b'a', b'r', 0x20];
121 const VERSION: [u8; 2] = [0x20, 0x00];
122 impl Header {
123     /// new header
newnull124     pub fn new() -> Self {
125         Self {
126             name: [0u8; 100],
127             mode: [0u8; 8],
128             uid: [0u8; 8],
129             gid: [0u8; 8],
130             size: [0u8; 12],
131             mtime: [0u8; 12],
132             chksum: [0u8; 8],
133             typeflage: [0u8; 1],
134             linkname: [0u8; 100],
135             magic: MAGIC,
136             version: VERSION,
137             uname: [0u8; 32],
138             gname: [0u8; 32],
139             devmajor: [0u8; 8],
140             devminor: [0u8; 8],
141             prefix: [0u8; 155],
142             pad: [0u8; 12],
143         }
144     }
145 
146     /// new header form data
create_from_raw_datanull147     pub fn create_from_raw_data(data: &[u8; 512]) -> Self {
148         Self {
149             name: data[0..100].try_into().unwrap(),
150             mode: data[100..108].try_into().unwrap(),
151             uid: data[108..116].try_into().unwrap(),
152             gid: data[116..124].try_into().unwrap(),
153             size: data[124..136].try_into().unwrap(),
154             mtime: data[136..148].try_into().unwrap(),
155             chksum: data[148..156].try_into().unwrap(),
156             typeflage: data[156..157].try_into().unwrap(),
157             linkname: data[157..257].try_into().unwrap(),
158             magic: data[257..263].try_into().unwrap(),
159             version: data[263..265].try_into().unwrap(),
160             uname: data[265..297].try_into().unwrap(),
161             gname: data[297..329].try_into().unwrap(),
162             devmajor: data[329..337].try_into().unwrap(),
163             devminor: data[337..345].try_into().unwrap(),
164             prefix: data[345..500].try_into().unwrap(),
165             pad: data[500..512].try_into().unwrap(),
166         }
167     }
168 
convert_octal_string_to_u32null169     fn convert_octal_string_to_u32(data: &[u8]) -> u32 {
170         let Ok(mut str) = String::from_utf8(data.to_vec()) else {
171             crate::error!("from_utf8 failed");
172             return 0;
173         };
174         str = str.replace('\0', "");
175         match u32::from_str_radix(&str, 8) {
176             Ok(num) => num,
177             Err(e) => {
178                 crate::error!("convert_octal_string_to_u32 failed, {e}");
179                 0
180             }
181         }
182     }
183 
convert_u32_to_octal_stringnull184     fn convert_u32_to_octal_string(dst: &mut [u8], len: usize, data: u32) {
185         let str = format!("{:0width$o}\0", data, width = len - 1);
186         let bytes = str.as_bytes();
187         dst.copy_from_slice(bytes);
188     }
189 
190     /// Get name
namenull191     pub fn name(&self) -> String {
192         let Ok(prefix) = String::from_utf8(self.prefix.to_vec()) else {
193             return String::new();
194         };
195         let Ok(name) = String::from_utf8(self.name.to_vec()) else {
196             return String::new();
197         };
198 
199         let aa = prefix + &name;
200         aa.replace('\0', "")
201     }
202 
203     /// Update name
updata_namenull204     pub fn updata_name(&mut self, name: String) -> Result<(), &str> {
205         let mut bytes = name.into_bytes();
206         bytes.push(b'\0');
207         let bytes = &bytes[..];
208 
209         if bytes.len() > HEADER_LEN as usize {
210             return Err("file name is too long");
211         }
212 
213         match bytes.len() {
214             0..=100 => {
215                 self.name[..bytes.len()].copy_from_slice(bytes);
216             }
217             101..=254 => {
218                 let index = bytes.len() - 100;
219                 let (prefix, name) = bytes.split_at(index);
220                 self.prefix[..prefix.len()].copy_from_slice(prefix);
221                 self.name.copy_from_slice(name);
222             }
223             _ => {
224                 return Err("file name is too long");
225             }
226         }
227 
228         Ok(())
229     }
230 
231     #[allow(unused)]
modenull232     fn mode(&self) -> u32 {
233         Header::convert_octal_string_to_u32(&self.mode)
234     }
235 
236     ///  Update file mode
237     #[allow(unused)]
updata_modenull238     pub fn updata_mode(&mut self) {
239         Header::convert_u32_to_octal_string(&mut self.mode, 8, 365);
240     }
241 
242     /// Get file size
sizenull243     pub fn size(&self) -> u64 {
244         Header::convert_octal_string_to_u32(&self.size) as u64
245     }
246 
247     /// Update file size
updata_sizenull248     pub fn updata_size(&mut self, len: usize) {
249         Header::convert_u32_to_octal_string(&mut self.size, 12, len as u32);
250     }
251 
252     /// Get file type
file_typenull253     pub fn file_type(&self) -> TypeFlage {
254         TypeFlage::try_from(self.typeflage[0]).unwrap_or(TypeFlage::Invalid)
255     }
256 
257     /// Update file type
updata_file_typenull258     pub fn updata_file_type(&mut self, file_type: TypeFlage) {
259         self.typeflage[0] = file_type as u8;
260     }
261 
262     /// file type is invalid
is_invalidnull263     pub fn is_invalid(&self) -> bool {
264         self.file_type() == TypeFlage::Invalid
265     }
266 
updata_check_sumnull267     fn updata_check_sum(&mut self) {
268         let mut sum: u32 = 0;
269         let mut check_sum = |data: &[u8]| {
270             for it in data {
271                 sum += *it as u32;
272             }
273         };
274         check_sum(&self.name);
275         check_sum(&self.mode);
276         check_sum(&self.uid);
277         check_sum(&self.gid);
278         check_sum(&self.size);
279         check_sum(&self.mtime);
280         // check_sum(&self.chksum);
281         check_sum(&self.typeflage);
282         check_sum(&self.linkname);
283         check_sum(&self.magic);
284         check_sum(&self.version);
285         check_sum(&self.uname);
286         check_sum(&self.gname);
287         check_sum(&self.devmajor);
288         check_sum(&self.devminor);
289         check_sum(&self.prefix);
290         check_sum(&self.pad);
291         sum += SUM_CONSTANT;
292         Header::convert_u32_to_octal_string(&mut self.chksum, 8, sum);
293     }
294 
295     /// Get bytes
get_bytesnull296     pub fn get_bytes(&mut self, bytes: &mut [u8; 512]) {
297         self.updata_check_sum();
298         let mut start = 0;
299         let mut end = 0;
300         let mut copy_data = |data: &[u8]| {
301             start = end;
302             end = start + data.len();
303             bytes[start..end].copy_from_slice(data);
304         };
305         copy_data(&self.name);
306         copy_data(&self.mode);
307         copy_data(&self.uid);
308         copy_data(&self.gid);
309         copy_data(&self.size);
310         copy_data(&self.mtime);
311         copy_data(&self.chksum);
312         copy_data(&self.typeflage);
313         copy_data(&self.linkname);
314         copy_data(&self.magic);
315         copy_data(&self.version);
316         copy_data(&self.uname);
317         copy_data(&self.gname);
318         copy_data(&self.devmajor);
319         copy_data(&self.devminor);
320         copy_data(&self.prefix);
321         copy_data(&self.pad);
322     }
323 }
324