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