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