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 //! entry 16 17 use std::{ 18 fs, 19 io::{self, Write}, 20 path::{Path, PathBuf}, 21 }; 22 23 use crate::tar::header::{self, Header, TypeFlage, HEADER_LEN}; 24 #[allow(unused)] 25 use crate::utils::hdc_log::*; 26 27 /// Entry 28 pub struct Entry { 29 /// 每个文件的头 30 header: Header, 31 /// 文件大小 (即data数组中不包含填充字段的长度) 32 need_size: u64, 33 /// 路径前缀,不为空时,保存到header时去掉前缀,读取文件时进行拼接 34 // prefix: String, 35 prefix: PathBuf, 36 /// 文件数据 37 data: Vec<u8>, 38 } 39 40 impl Entry { 41 /// new entry form file newnull42 pub fn new(prefix: PathBuf, path: &str) -> Self { 43 let mut entry = Self { 44 header: Header::new(), 45 need_size: 0, 46 prefix, 47 data: Vec::new(), 48 }; 49 match fs::metadata(path) { 50 Ok(metadata) => { 51 let file_size = metadata.len(); 52 if metadata.is_file() { 53 entry.header.updata_size(file_size as usize); 54 entry.need_size = file_size; 55 entry.header.updata_file_type(TypeFlage::OrdinaryFile); 56 } else if metadata.is_dir() { 57 entry.header.updata_size(0); 58 entry.header.updata_file_type(TypeFlage::Directory); 59 } 60 } 61 Err(_) => return entry, 62 }; 63 64 if let Err(e) = entry.updata_name(path.to_string()) { 65 crate::error!("{e}"); 66 } 67 68 entry 69 } 70 71 /// new entry from data create_from_raw_datanull72 pub fn create_from_raw_data(data: &[u8; 512]) -> Result<Self, std::io::Error> { 73 let header = Header::create_from_raw_data(data); 74 let need_size = header.size(); 75 if header.is_invalid() { 76 return Err(std::io::Error::new( 77 std::io::ErrorKind::Other, 78 "header is invalid", 79 )); 80 } 81 Ok(Self { 82 header, 83 need_size, 84 prefix: PathBuf::new(), 85 data: Vec::new(), 86 }) 87 } 88 89 /// Get name namenull90 pub fn name(&self) -> String { 91 let name = self.prefix.join(self.header.name()); 92 name.display().to_string() 93 } 94 95 /// updata name updata_namenull96 pub fn updata_name(&mut self, name: String) -> Result<(), &str> { 97 if self.prefix.components().count() != 0 { 98 let name_path = Path::new(&name); 99 if let Ok(sort_path) = name_path.strip_prefix(self.prefix.clone()) { 100 return self.header.updata_name(sort_path.display().to_string()); 101 } 102 } 103 self.header.updata_name(name) 104 } 105 106 /// The data read is of the expected size is_finishnull107 pub fn is_finish(&self) -> bool { 108 self.need_size == 0 109 } 110 111 /// Type is invalid is_invalidnull112 pub fn is_invalid(&self) -> bool { 113 self.header.is_invalid() 114 } 115 116 /// Add data to entry add_datanull117 pub fn add_data(&mut self, data: &[u8]) { 118 if self.need_size == 0 { 119 return; 120 } 121 if self.need_size > data.len() as u64 { 122 self.data.extend_from_slice(data); 123 self.need_size -= data.len() as u64; 124 } else { 125 self.data 126 .extend_from_slice(&data[..self.need_size as usize]); 127 self.need_size = 0; 128 } 129 } 130 131 /// Get file size sizenull132 pub fn size(&self) -> u64 { 133 self.header.size() 134 } 135 136 /// Write entry to file write_to_filenull137 pub fn write_to_file(&self, path: &Path) -> Result<(), std::io::Error> { 138 if !self.is_finish() { 139 return Err(io::Error::new( 140 io::ErrorKind::Other, 141 format!("{} data is not load finish", self.name()), 142 )); 143 } 144 145 match self.header.file_type() { 146 header::TypeFlage::OrdinaryFile => { 147 let file_path = path.join(self.name()); 148 let mut f = fs::OpenOptions::new() 149 .read(true) 150 .write(true) 151 .create(true) 152 .open(file_path)?; 153 f.write_all(&self.data)?; 154 } 155 header::TypeFlage::Directory => { 156 let dir_path = path.join(self.name()); 157 fs::create_dir_all(dir_path)?; 158 } 159 file_type => { 160 return Err(io::Error::new( 161 io::ErrorKind::Other, 162 format!("{:?} not yet support. {}", file_type, self.name()), 163 )); 164 } 165 } 166 167 Ok(()) 168 } 169 170 /// Read the file content from the file pointed to by name() to _file read_data_to_filenull171 pub fn read_data_to_file(&mut self, _file: &mut fs::File) -> Result<(), std::io::Error> { 172 match self.header.file_type() { 173 TypeFlage::OrdinaryFile => { 174 let mut buff = [0u8; 512]; 175 self.header.get_bytes(&mut buff); 176 _file.write_all(&buff)?; 177 let mut in_file = fs::File::open(self.name())?; 178 io::copy(&mut in_file, _file)?; 179 let pading = HEADER_LEN - (self.need_size % HEADER_LEN); 180 if pading < HEADER_LEN { 181 let empty_buff = [0u8; 512]; 182 _file.write_all(&empty_buff[..pading as usize])?; 183 } 184 } 185 TypeFlage::Directory => { 186 let mut buff = [0u8; 512]; 187 self.header.get_bytes(&mut buff); 188 _file.write_all(&buff)?; 189 } 190 file_type => { 191 return Err(io::Error::new( 192 io::ErrorKind::Other, 193 format!("file type error, {:?}, path: {}", file_type, self.name()), 194 )) 195 } 196 }; 197 Ok(()) 198 } 199 } 200