1cc290419Sopenharmony_ci/* 2cc290419Sopenharmony_ci * Copyright (C) 2024 Huawei Device Co., Ltd. 3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License. 5cc290419Sopenharmony_ci * You may obtain a copy of the License at 6cc290419Sopenharmony_ci * 7cc290419Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8cc290419Sopenharmony_ci * 9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and 13cc290419Sopenharmony_ci * limitations under the License. 14cc290419Sopenharmony_ci */ 15cc290419Sopenharmony_ci//! entry 16cc290419Sopenharmony_ci 17cc290419Sopenharmony_ciuse std::{ 18cc290419Sopenharmony_ci fs, 19cc290419Sopenharmony_ci io::{self, Write}, 20cc290419Sopenharmony_ci path::{Path, PathBuf}, 21cc290419Sopenharmony_ci}; 22cc290419Sopenharmony_ci 23cc290419Sopenharmony_ciuse crate::tar::header::{self, Header, TypeFlage, HEADER_LEN}; 24cc290419Sopenharmony_ci#[allow(unused)] 25cc290419Sopenharmony_ciuse crate::utils::hdc_log::*; 26cc290419Sopenharmony_ci 27cc290419Sopenharmony_ci/// Entry 28cc290419Sopenharmony_cipub struct Entry { 29cc290419Sopenharmony_ci /// 每个文件的头 30cc290419Sopenharmony_ci header: Header, 31cc290419Sopenharmony_ci /// 文件大小 (即data数组中不包含填充字段的长度) 32cc290419Sopenharmony_ci need_size: u64, 33cc290419Sopenharmony_ci /// 路径前缀,不为空时,保存到header时去掉前缀,读取文件时进行拼接 34cc290419Sopenharmony_ci // prefix: String, 35cc290419Sopenharmony_ci prefix: PathBuf, 36cc290419Sopenharmony_ci /// 文件数据 37cc290419Sopenharmony_ci data: Vec<u8>, 38cc290419Sopenharmony_ci} 39cc290419Sopenharmony_ci 40cc290419Sopenharmony_ciimpl Entry { 41cc290419Sopenharmony_ci /// new entry form file 42cc290419Sopenharmony_ci pub fn new(prefix: PathBuf, path: &str) -> Self { 43cc290419Sopenharmony_ci let mut entry = Self { 44cc290419Sopenharmony_ci header: Header::new(), 45cc290419Sopenharmony_ci need_size: 0, 46cc290419Sopenharmony_ci prefix, 47cc290419Sopenharmony_ci data: Vec::new(), 48cc290419Sopenharmony_ci }; 49cc290419Sopenharmony_ci match fs::metadata(path) { 50cc290419Sopenharmony_ci Ok(metadata) => { 51cc290419Sopenharmony_ci let file_size = metadata.len(); 52cc290419Sopenharmony_ci if metadata.is_file() { 53cc290419Sopenharmony_ci entry.header.updata_size(file_size as usize); 54cc290419Sopenharmony_ci entry.need_size = file_size; 55cc290419Sopenharmony_ci entry.header.updata_file_type(TypeFlage::OrdinaryFile); 56cc290419Sopenharmony_ci } else if metadata.is_dir() { 57cc290419Sopenharmony_ci entry.header.updata_size(0); 58cc290419Sopenharmony_ci entry.header.updata_file_type(TypeFlage::Directory); 59cc290419Sopenharmony_ci } 60cc290419Sopenharmony_ci } 61cc290419Sopenharmony_ci Err(_) => return entry, 62cc290419Sopenharmony_ci }; 63cc290419Sopenharmony_ci 64cc290419Sopenharmony_ci if let Err(e) = entry.updata_name(path.to_string()) { 65cc290419Sopenharmony_ci crate::error!("{e}"); 66cc290419Sopenharmony_ci } 67cc290419Sopenharmony_ci 68cc290419Sopenharmony_ci entry 69cc290419Sopenharmony_ci } 70cc290419Sopenharmony_ci 71cc290419Sopenharmony_ci /// new entry from data 72cc290419Sopenharmony_ci pub fn create_from_raw_data(data: &[u8; 512]) -> Result<Self, std::io::Error> { 73cc290419Sopenharmony_ci let header = Header::create_from_raw_data(data); 74cc290419Sopenharmony_ci let need_size = header.size(); 75cc290419Sopenharmony_ci if header.is_invalid() { 76cc290419Sopenharmony_ci return Err(std::io::Error::new( 77cc290419Sopenharmony_ci std::io::ErrorKind::Other, 78cc290419Sopenharmony_ci "header is invalid", 79cc290419Sopenharmony_ci )); 80cc290419Sopenharmony_ci } 81cc290419Sopenharmony_ci Ok(Self { 82cc290419Sopenharmony_ci header, 83cc290419Sopenharmony_ci need_size, 84cc290419Sopenharmony_ci prefix: PathBuf::new(), 85cc290419Sopenharmony_ci data: Vec::new(), 86cc290419Sopenharmony_ci }) 87cc290419Sopenharmony_ci } 88cc290419Sopenharmony_ci 89cc290419Sopenharmony_ci /// Get name 90cc290419Sopenharmony_ci pub fn name(&self) -> String { 91cc290419Sopenharmony_ci let name = self.prefix.join(self.header.name()); 92cc290419Sopenharmony_ci name.display().to_string() 93cc290419Sopenharmony_ci } 94cc290419Sopenharmony_ci 95cc290419Sopenharmony_ci /// updata name 96cc290419Sopenharmony_ci pub fn updata_name(&mut self, name: String) -> Result<(), &str> { 97cc290419Sopenharmony_ci if self.prefix.components().count() != 0 { 98cc290419Sopenharmony_ci let name_path = Path::new(&name); 99cc290419Sopenharmony_ci if let Ok(sort_path) = name_path.strip_prefix(self.prefix.clone()) { 100cc290419Sopenharmony_ci return self.header.updata_name(sort_path.display().to_string()); 101cc290419Sopenharmony_ci } 102cc290419Sopenharmony_ci } 103cc290419Sopenharmony_ci self.header.updata_name(name) 104cc290419Sopenharmony_ci } 105cc290419Sopenharmony_ci 106cc290419Sopenharmony_ci /// The data read is of the expected size 107cc290419Sopenharmony_ci pub fn is_finish(&self) -> bool { 108cc290419Sopenharmony_ci self.need_size == 0 109cc290419Sopenharmony_ci } 110cc290419Sopenharmony_ci 111cc290419Sopenharmony_ci /// Type is invalid 112cc290419Sopenharmony_ci pub fn is_invalid(&self) -> bool { 113cc290419Sopenharmony_ci self.header.is_invalid() 114cc290419Sopenharmony_ci } 115cc290419Sopenharmony_ci 116cc290419Sopenharmony_ci /// Add data to entry 117cc290419Sopenharmony_ci pub fn add_data(&mut self, data: &[u8]) { 118cc290419Sopenharmony_ci if self.need_size == 0 { 119cc290419Sopenharmony_ci return; 120cc290419Sopenharmony_ci } 121cc290419Sopenharmony_ci if self.need_size > data.len() as u64 { 122cc290419Sopenharmony_ci self.data.extend_from_slice(data); 123cc290419Sopenharmony_ci self.need_size -= data.len() as u64; 124cc290419Sopenharmony_ci } else { 125cc290419Sopenharmony_ci self.data 126cc290419Sopenharmony_ci .extend_from_slice(&data[..self.need_size as usize]); 127cc290419Sopenharmony_ci self.need_size = 0; 128cc290419Sopenharmony_ci } 129cc290419Sopenharmony_ci } 130cc290419Sopenharmony_ci 131cc290419Sopenharmony_ci /// Get file size 132cc290419Sopenharmony_ci pub fn size(&self) -> u64 { 133cc290419Sopenharmony_ci self.header.size() 134cc290419Sopenharmony_ci } 135cc290419Sopenharmony_ci 136cc290419Sopenharmony_ci /// Write entry to file 137cc290419Sopenharmony_ci pub fn write_to_file(&self, path: &Path) -> Result<(), std::io::Error> { 138cc290419Sopenharmony_ci if !self.is_finish() { 139cc290419Sopenharmony_ci return Err(io::Error::new( 140cc290419Sopenharmony_ci io::ErrorKind::Other, 141cc290419Sopenharmony_ci format!("{} data is not load finish", self.name()), 142cc290419Sopenharmony_ci )); 143cc290419Sopenharmony_ci } 144cc290419Sopenharmony_ci 145cc290419Sopenharmony_ci match self.header.file_type() { 146cc290419Sopenharmony_ci header::TypeFlage::OrdinaryFile => { 147cc290419Sopenharmony_ci let file_path = path.join(self.name()); 148cc290419Sopenharmony_ci let mut f = fs::OpenOptions::new() 149cc290419Sopenharmony_ci .read(true) 150cc290419Sopenharmony_ci .write(true) 151cc290419Sopenharmony_ci .create(true) 152cc290419Sopenharmony_ci .open(file_path)?; 153cc290419Sopenharmony_ci f.write_all(&self.data)?; 154cc290419Sopenharmony_ci } 155cc290419Sopenharmony_ci header::TypeFlage::Directory => { 156cc290419Sopenharmony_ci let dir_path = path.join(self.name()); 157cc290419Sopenharmony_ci fs::create_dir_all(dir_path)?; 158cc290419Sopenharmony_ci } 159cc290419Sopenharmony_ci file_type => { 160cc290419Sopenharmony_ci return Err(io::Error::new( 161cc290419Sopenharmony_ci io::ErrorKind::Other, 162cc290419Sopenharmony_ci format!("{:?} not yet support. {}", file_type, self.name()), 163cc290419Sopenharmony_ci )); 164cc290419Sopenharmony_ci } 165cc290419Sopenharmony_ci } 166cc290419Sopenharmony_ci 167cc290419Sopenharmony_ci Ok(()) 168cc290419Sopenharmony_ci } 169cc290419Sopenharmony_ci 170cc290419Sopenharmony_ci /// Read the file content from the file pointed to by name() to _file 171cc290419Sopenharmony_ci pub fn read_data_to_file(&mut self, _file: &mut fs::File) -> Result<(), std::io::Error> { 172cc290419Sopenharmony_ci match self.header.file_type() { 173cc290419Sopenharmony_ci TypeFlage::OrdinaryFile => { 174cc290419Sopenharmony_ci let mut buff = [0u8; 512]; 175cc290419Sopenharmony_ci self.header.get_bytes(&mut buff); 176cc290419Sopenharmony_ci _file.write_all(&buff)?; 177cc290419Sopenharmony_ci let mut in_file = fs::File::open(self.name())?; 178cc290419Sopenharmony_ci io::copy(&mut in_file, _file)?; 179cc290419Sopenharmony_ci let pading = HEADER_LEN - (self.need_size % HEADER_LEN); 180cc290419Sopenharmony_ci if pading < HEADER_LEN { 181cc290419Sopenharmony_ci let empty_buff = [0u8; 512]; 182cc290419Sopenharmony_ci _file.write_all(&empty_buff[..pading as usize])?; 183cc290419Sopenharmony_ci } 184cc290419Sopenharmony_ci } 185cc290419Sopenharmony_ci TypeFlage::Directory => { 186cc290419Sopenharmony_ci let mut buff = [0u8; 512]; 187cc290419Sopenharmony_ci self.header.get_bytes(&mut buff); 188cc290419Sopenharmony_ci _file.write_all(&buff)?; 189cc290419Sopenharmony_ci } 190cc290419Sopenharmony_ci file_type => { 191cc290419Sopenharmony_ci return Err(io::Error::new( 192cc290419Sopenharmony_ci io::ErrorKind::Other, 193cc290419Sopenharmony_ci format!("file type error, {:?}, path: {}", file_type, self.name()), 194cc290419Sopenharmony_ci )) 195cc290419Sopenharmony_ci } 196cc290419Sopenharmony_ci }; 197cc290419Sopenharmony_ci Ok(()) 198cc290419Sopenharmony_ci } 199cc290419Sopenharmony_ci} 200