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