* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#[allow(unused)]
use crate::utils::hdc_log::*;
use core::fmt;
use std::fmt::Debug;
pub const HEADER_LEN: u64 = 512;
const SUM_CONSTANT: u32 = 256;
#[repr(u8)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum TypeFlage {
Invalid = 0u8,
OrdinaryFile = 48u8,
HardLink = 49u8,
SoftLink = 50u8,
CharacterDevice = 51u8,
BlockDevice = 52u8,
Directory = 53u8,
Fifo = 54u8,
Reserve = 55u8,
}
impl TryFrom<u8> for TypeFlage {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0u8 => Ok(Self::Invalid),
48u8 => Ok(Self::OrdinaryFile),
49u8 => Ok(Self::HardLink),
50u8 => Ok(Self::SoftLink),
51u8 => Ok(Self::CharacterDevice),
52u8 => Ok(Self::BlockDevice),
53u8 => Ok(Self::Directory),
54u8 => Ok(Self::Fifo),
55u8 => Ok(Self::Reserve),
_ => Ok(Self::Invalid),
}
}
}
pub struct Header {
name: [u8; 100],
mode: [u8; 8],
uid: [u8; 8],
gid: [u8; 8],
size: [u8; 12],
mtime: [u8; 12],
chksum: [u8; 8],
typeflage: [u8; 1],
linkname: [u8; 100],
magic: [u8; 6],
version: [u8; 2],
uname: [u8; 32],
gname: [u8; 32],
devmajor: [u8; 8],
devminor: [u8; 8],
prefix: [u8; 155],
pad: [u8; 12],
}
impl std::fmt::Debug for Header {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "name : {}\n", self.name())
}
}
impl Default for Header {
fn default() -> Self {
Self::new()
}
}
const MAGIC: [u8; 6] = [b'u', b's', b't', b'a', b'r', 0x20];
const VERSION: [u8; 2] = [0x20, 0x00];
impl Header {
pub fn new() -> Self {
Self {
name: [0u8; 100],
mode: [0u8; 8],
uid: [0u8; 8],
gid: [0u8; 8],
size: [0u8; 12],
mtime: [0u8; 12],
chksum: [0u8; 8],
typeflage: [0u8; 1],
linkname: [0u8; 100],
magic: MAGIC,
version: VERSION,
uname: [0u8; 32],
gname: [0u8; 32],
devmajor: [0u8; 8],
devminor: [0u8; 8],
prefix: [0u8; 155],
pad: [0u8; 12],
}
}
pub fn create_from_raw_data(data: &[u8; 512]) -> Self {
Self {
name: data[0..100].try_into().unwrap(),
mode: data[100..108].try_into().unwrap(),
uid: data[108..116].try_into().unwrap(),
gid: data[116..124].try_into().unwrap(),
size: data[124..136].try_into().unwrap(),
mtime: data[136..148].try_into().unwrap(),
chksum: data[148..156].try_into().unwrap(),
typeflage: data[156..157].try_into().unwrap(),
linkname: data[157..257].try_into().unwrap(),
magic: data[257..263].try_into().unwrap(),
version: data[263..265].try_into().unwrap(),
uname: data[265..297].try_into().unwrap(),
gname: data[297..329].try_into().unwrap(),
devmajor: data[329..337].try_into().unwrap(),
devminor: data[337..345].try_into().unwrap(),
prefix: data[345..500].try_into().unwrap(),
pad: data[500..512].try_into().unwrap(),
}
}
fn convert_octal_string_to_u32(data: &[u8]) -> u32 {
let Ok(mut str) = String::from_utf8(data.to_vec()) else {
crate::error!("from_utf8 failed");
return 0;
};
str = str.replace('\0', "");
match u32::from_str_radix(&str, 8) {
Ok(num) => num,
Err(e) => {
crate::error!("convert_octal_string_to_u32 failed, {e}");
0
}
}
}
fn convert_u32_to_octal_string(dst: &mut [u8], len: usize, data: u32) {
let str = format!("{:0width$o}\0", data, width = len - 1);
let bytes = str.as_bytes();
dst.copy_from_slice(bytes);
}
pub fn name(&self) -> String {
let Ok(prefix) = String::from_utf8(self.prefix.to_vec()) else {
return String::new();
};
let Ok(name) = String::from_utf8(self.name.to_vec()) else {
return String::new();
};
let aa = prefix + &name;
aa.replace('\0', "")
}
pub fn updata_name(&mut self, name: String) -> Result<(), &str> {
let mut bytes = name.into_bytes();
bytes.push(b'\0');
let bytes = &bytes[..];
if bytes.len() > HEADER_LEN as usize {
return Err("file name is too long");
}
match bytes.len() {
0..=100 => {
self.name[..bytes.len()].copy_from_slice(bytes);
}
101..=254 => {
let index = bytes.len() - 100;
let (prefix, name) = bytes.split_at(index);
self.prefix[..prefix.len()].copy_from_slice(prefix);
self.name.copy_from_slice(name);
}
_ => {
return Err("file name is too long");
}
}
Ok(())
}
#[allow(unused)]
fn mode(&self) -> u32 {
Header::convert_octal_string_to_u32(&self.mode)
}
#[allow(unused)]
pub fn updata_mode(&mut self) {
Header::convert_u32_to_octal_string(&mut self.mode, 8, 365);
}
pub fn size(&self) -> u64 {
Header::convert_octal_string_to_u32(&self.size) as u64
}
pub fn updata_size(&mut self, len: usize) {
Header::convert_u32_to_octal_string(&mut self.size, 12, len as u32);
}
pub fn file_type(&self) -> TypeFlage {
TypeFlage::try_from(self.typeflage[0]).unwrap_or(TypeFlage::Invalid)
}
pub fn updata_file_type(&mut self, file_type: TypeFlage) {
self.typeflage[0] = file_type as u8;
}
pub fn is_invalid(&self) -> bool {
self.file_type() == TypeFlage::Invalid
}
fn updata_check_sum(&mut self) {
let mut sum: u32 = 0;
let mut check_sum = |data: &[u8]| {
for it in data {
sum += *it as u32;
}
};
check_sum(&self.name);
check_sum(&self.mode);
check_sum(&self.uid);
check_sum(&self.gid);
check_sum(&self.size);
check_sum(&self.mtime);
check_sum(&self.typeflage);
check_sum(&self.linkname);
check_sum(&self.magic);
check_sum(&self.version);
check_sum(&self.uname);
check_sum(&self.gname);
check_sum(&self.devmajor);
check_sum(&self.devminor);
check_sum(&self.prefix);
check_sum(&self.pad);
sum += SUM_CONSTANT;
Header::convert_u32_to_octal_string(&mut self.chksum, 8, sum);
}
pub fn get_bytes(&mut self, bytes: &mut [u8; 512]) {
self.updata_check_sum();
let mut start = 0;
let mut end = 0;
let mut copy_data = |data: &[u8]| {
start = end;
end = start + data.len();
bytes[start..end].copy_from_slice(data);
};
copy_data(&self.name);
copy_data(&self.mode);
copy_data(&self.uid);
copy_data(&self.gid);
copy_data(&self.size);
copy_data(&self.mtime);
copy_data(&self.chksum);
copy_data(&self.typeflage);
copy_data(&self.linkname);
copy_data(&self.magic);
copy_data(&self.version);
copy_data(&self.uname);
copy_data(&self.gname);
copy_data(&self.devmajor);
copy_data(&self.devminor);
copy_data(&self.prefix);
copy_data(&self.pad);
}
}