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//! decompress
16cc290419Sopenharmony_ci
17cc290419Sopenharmony_ciuse std::{
18cc290419Sopenharmony_ci    fs,
19cc290419Sopenharmony_ci    io::{self, Read},
20cc290419Sopenharmony_ci    path::Path,
21cc290419Sopenharmony_ci};
22cc290419Sopenharmony_ci
23cc290419Sopenharmony_ciuse crate::tar::{entry::Entry, header};
24cc290419Sopenharmony_ci#[allow(unused)]
25cc290419Sopenharmony_ciuse crate::utils::hdc_log::*;
26cc290419Sopenharmony_ci
27cc290419Sopenharmony_ci/// Decomposes the tar package
28cc290419Sopenharmony_cipub struct Decompress {
29cc290419Sopenharmony_ci    entrys: Vec<Entry>,
30cc290419Sopenharmony_ci}
31cc290419Sopenharmony_ci
32cc290419Sopenharmony_ciimpl Decompress {
33cc290419Sopenharmony_ci    /// Decomposes tar
34cc290419Sopenharmony_ci    /// path: tar path
35cc290419Sopenharmony_ci    pub fn file(path: &str) -> Result<Decompress, io::Error> {
36cc290419Sopenharmony_ci        match fs::metadata(path) {
37cc290419Sopenharmony_ci            Ok(metadata) => {
38cc290419Sopenharmony_ci                let file_size = metadata.len();
39cc290419Sopenharmony_ci                if file_size == 0 || file_size % header::HEADER_LEN as u64 != 0 {
40cc290419Sopenharmony_ci                    return Err(io::Error::new(
41cc290419Sopenharmony_ci                        io::ErrorKind::InvalidInput,
42cc290419Sopenharmony_ci                        format!("{path} is not tar file"),
43cc290419Sopenharmony_ci                    ));
44cc290419Sopenharmony_ci                }
45cc290419Sopenharmony_ci            }
46cc290419Sopenharmony_ci            Err(e) => return Err(e),
47cc290419Sopenharmony_ci        };
48cc290419Sopenharmony_ci        let mut f = fs::File::open(path)?;
49cc290419Sopenharmony_ci        let mut buff = [0u8; header::HEADER_LEN as usize];
50cc290419Sopenharmony_ci
51cc290419Sopenharmony_ci        let mut decompress = Self { entrys: Vec::new() };
52cc290419Sopenharmony_ci
53cc290419Sopenharmony_ci        let mut entry = None;
54cc290419Sopenharmony_ci        loop {
55cc290419Sopenharmony_ci            match f.read(&mut buff)? {
56cc290419Sopenharmony_ci                512 => match entry {
57cc290419Sopenharmony_ci                    None => {
58cc290419Sopenharmony_ci                        if let Ok(p_entry) = Entry::create_from_raw_data(&buff) {
59cc290419Sopenharmony_ci                            if p_entry.is_finish() {
60cc290419Sopenharmony_ci                                decompress.entrys.push(p_entry);
61cc290419Sopenharmony_ci                            } else {
62cc290419Sopenharmony_ci                                entry = Some(p_entry);
63cc290419Sopenharmony_ci                            }
64cc290419Sopenharmony_ci                        }
65cc290419Sopenharmony_ci                        continue;
66cc290419Sopenharmony_ci                    }
67cc290419Sopenharmony_ci                    Some(ref mut p_entry) => {
68cc290419Sopenharmony_ci                        p_entry.add_data(&buff);
69cc290419Sopenharmony_ci                        if p_entry.is_finish() {
70cc290419Sopenharmony_ci                            decompress.entrys.push(entry.unwrap());
71cc290419Sopenharmony_ci                            entry = None;
72cc290419Sopenharmony_ci                        }
73cc290419Sopenharmony_ci                    }
74cc290419Sopenharmony_ci                },
75cc290419Sopenharmony_ci                0 => break,
76cc290419Sopenharmony_ci                n => {
77cc290419Sopenharmony_ci                    crate::error!("read error n {n}");
78cc290419Sopenharmony_ci                    break;
79cc290419Sopenharmony_ci                }
80cc290419Sopenharmony_ci            }
81cc290419Sopenharmony_ci        }
82cc290419Sopenharmony_ci
83cc290419Sopenharmony_ci        Ok(decompress)
84cc290419Sopenharmony_ci    }
85cc290419Sopenharmony_ci
86cc290419Sopenharmony_ci    /// 将文件解压到文件夹,传入路径为空则是当前文件夹
87cc290419Sopenharmony_ci    pub fn decompress(&self, prefix: &str) -> io::Result<()> {
88cc290419Sopenharmony_ci        let prefix = if !prefix.is_empty() { prefix } else { "./" };
89cc290419Sopenharmony_ci
90cc290419Sopenharmony_ci        let prefix_path = Path::new(prefix);
91cc290419Sopenharmony_ci
92cc290419Sopenharmony_ci        if prefix_path.exists() {
93cc290419Sopenharmony_ci            if prefix_path.is_file() {
94cc290419Sopenharmony_ci                return Err(io::Error::new(
95cc290419Sopenharmony_ci                    io::ErrorKind::InvalidInput,
96cc290419Sopenharmony_ci                    format!("{} is not a dir", prefix),
97cc290419Sopenharmony_ci                ));
98cc290419Sopenharmony_ci            }
99cc290419Sopenharmony_ci        } else {
100cc290419Sopenharmony_ci            crate::debug!("need create dir {}", prefix);
101cc290419Sopenharmony_ci            fs::create_dir_all(prefix)?;
102cc290419Sopenharmony_ci        }
103cc290419Sopenharmony_ci
104cc290419Sopenharmony_ci        for entry in &self.entrys {
105cc290419Sopenharmony_ci            if !entry.is_finish() {
106cc290419Sopenharmony_ci                crate::error!("file data is not load");
107cc290419Sopenharmony_ci                continue;
108cc290419Sopenharmony_ci            }
109cc290419Sopenharmony_ci            if let Err(e) = entry.write_to_file(prefix_path) {
110cc290419Sopenharmony_ci                crate::error!("entry.write_to_file failed: {}", e);
111cc290419Sopenharmony_ci            }
112cc290419Sopenharmony_ci        }
113cc290419Sopenharmony_ci
114cc290419Sopenharmony_ci        Ok(())
115cc290419Sopenharmony_ci    }
116cc290419Sopenharmony_ci}
117