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 //! compress
16 
17 use std::{
18     fs,
19     io::{self, Error},
20     path::{Path, PathBuf},
21 };
22 
23 use crate::tar::entry::Entry;
24 #[allow(unused)]
25 use crate::utils::hdc_log::*;
26 
27 /// Compress tar
28 #[derive(Default)]
29 pub struct Compress {
30     entrys: Vec<Entry>,
31     prefix: PathBuf,
32     max_count: usize,
33 }
34 
35 impl Compress {
36     /// new Compress
newnull37     pub fn new() -> Self {
38         Self {
39             entrys: Vec::new(),
40             prefix: PathBuf::new(),
41             max_count: 0,
42         }
43     }
44 
45     /// updata prefix
updata_prefixnull46     pub fn updata_prefix(&mut self, prefix: PathBuf) {
47         self.prefix = prefix;
48     }
49 
50     /// updata max conunt
51     /// default: 0, no limit
52     /// other: Maximum number of entries allowed to be saved
updata_max_countnull53     pub fn updata_max_count(&mut self, count: usize) {
54         self.max_count = count;
55     }
56 
add_path_recursionnull57     fn add_path_recursion(&mut self, path: &Path) -> io::Result<()> {
58         if !path.is_dir() {
59             self.add_entry(&path.display().to_string())?;
60             return Ok(());
61         }
62 
63         self.add_entry(&path.display().to_string())?;
64 
65         for entry in fs::read_dir(path)? {
66             let entry = entry?;
67             let entry_path = entry.path();
68             self.add_path_recursion(&entry_path)?;
69         }
70 
71         Ok(())
72     }
73 
74     /// Add a path that needs to be packaged
add_pathnull75     pub fn add_path(&mut self, path: &Path) -> io::Result<()> {
76         self.add_path_recursion(path)
77     }
78 
add_entrynull79     fn add_entry(&mut self, file: &str) -> io::Result<()> {
80         if self.max_count > 0 && self.entrys.len() > self.max_count {
81             return Err(Error::new(
82                 io::ErrorKind::Other,
83                 format!(
84                     "Exceeded the set maximum value, the maximum value is set to {}",
85                     self.max_count
86                 ),
87             ));
88         }
89 
90         if let Some(prefix) = self.prefix.to_str() {
91             if prefix == file {
92                 crate::debug!("Ignoring compressed root directory");
93                 return Ok(());
94             }
95         }
96 
97         let entry = Entry::new(self.prefix.clone(), file);
98         self.entrys.push(entry);
99 
100         Ok(())
101     }
102 
103     /// 开始将数据写入压缩包
compressnull104     pub fn compress(&mut self, file_path: PathBuf) -> io::Result<()> {
105         if file_path.exists() && file_path.is_dir() {
106             return Err(io::Error::new(
107                 io::ErrorKind::InvalidInput,
108                 format!("{} is not a file", file_path.display()),
109             ));
110         }
111 
112         let mut f = fs::OpenOptions::new()
113             .read(true)
114             .write(true)
115             .create(true)
116             .truncate(true)
117             .open(file_path)?;
118         for entry in &mut self.entrys {
119             entry.read_data_to_file(&mut f)?;
120         }
121 
122         Ok(())
123     }
124 }
125