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