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