1 /*
2  * Copyright (C) 2023 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 //! base
16 #![allow(missing_docs)]
17 
18 use crate::config::{TLV_MIN_LEN, TLV_TAG_LEN, TLV_VAL_INVALID_LEN, TLV_VAL_LEN, TLV_VAL_MAXLEN};
19 use libc::{c_char, c_int};
20 #[cfg(not(feature = "host"))]
21 use libc::{SIGPIPE, SIGALRM, SIGTTIN, SIGTTOU, SIG_IGN, SIG_DFL, sighandler_t};
22 use std::collections::HashMap;
23 use std::{env, ffi::CString};
24 use std::path::{PathBuf, Path};
25 
26 extern "C" {
ProgramMutexnull27     fn ProgramMutex(procname: *const c_char, checkOrNew: bool, tmpDir: *const c_char) -> c_int;
28 }
29 
30 pub struct Base {}
31 
32 pub static GLOBAL_SERVER_NAME: &str = "HDCServer";
33 
34 impl Base {
split_command_to_argsnull35     pub fn split_command_to_args(command_line: &String) -> (Vec<String>, u32) {
36         let mut argv: Vec<String> = Vec::new();
37         let mut argc = 0;
38         let _a = 0;
39         let mut is_quoted = false;
40         let mut is_text = false;
41         let mut is_space = true;
42 
43         let len = command_line.len();
44         if len < 1 {
45             return (Vec::new(), 0);
46         }
47         argv.push(String::new());
48         for _a in command_line.chars() {
49             if is_quoted {
50                 if _a == '\"' {
51                     is_quoted = false;
52                 } else {
53                     argv.last_mut().unwrap().push(_a);
54                 }
55             } else {
56                 match _a {
57                     '\"' => {
58                         is_quoted = true;
59                         is_text = true;
60                         if is_space {
61                             argc += 1;
62                         }
63                         is_space = false;
64                     }
65                     x if x == ' ' || x == '\t' || x == '\n' || x == '\r' => {
66                         if is_text {
67                             argv.push(String::new());
68                         }
69                         is_text = false;
70                         is_space = true;
71                     }
72                     _ => {
73                         is_text = true;
74                         if is_space {
75                             argc += 1;
76                         }
77                         argv.last_mut().unwrap().push(_a);
78                         is_space = false;
79                     }
80                 }
81             }
82         }
83 
84         (argv, argc)
85     }
86 
get_path_sepnull87     pub fn get_path_sep() -> char {
88         if cfg!(target_os = "windows") {
89             '\\'
90         } else {
91             '/'
92         }
93     }
94 
get_charnull95     pub fn get_char(str: &str, index: usize) -> char {
96         str.chars().nth(index).unwrap()
97     }
98 
is_absolute_pathnull99     pub fn is_absolute_path(path: &str) -> bool {
100         if cfg!(target_os = "windows") {
101             let tmp = path.to_lowercase();
102             let p = tmp.as_str();
103             p.len() >= 3
104                 && (Self::get_char(p, 0) >= 'a' && Self::get_char(p, 0) <= 'z')
105                 && Self::get_char(p, 1) == ':'
106                 && Self::get_char(p, 2) == '\\'
107         } else {
108             path.starts_with('/')
109         }
110     }
111 
get_file_namenull112     pub fn get_file_name(s: &mut String) -> Option<String> {
113         let temp = s.to_owned();
114         let chars: std::str::Chars<'_> = temp.chars();
115         let mut result = String::new();
116         let mut len = (chars.clone().count() - 1) as i32;
117         while len >= 0 && chars.clone().nth(len as usize) == Some(Self::get_path_sep()) {
118             len -= 1;
119         }
120         let begin = len;
121         while len >= 0 && chars.clone().nth(len as usize) != Some(Self::get_path_sep()) {
122             len -= 1;
123         }
124         for i in (len + 1) as usize..(begin + 1) as usize {
125             result.push(chars.clone().nth(i).unwrap());
126         }
127         Some(result)
128     }
129 
extract_relative_pathnull130     pub fn extract_relative_path(_cwd: &str, mut _path: &str) -> String {
131         if !Base::is_absolute_path(_path) {
132             let mut path2 = _cwd.to_owned();
133             path2.push_str(_path);
134             return path2;
135         }
136         _path.to_owned()
137     }
138 
combinenull139     pub fn combine(src1: String, src2: String) -> String {
140         let path_sep = Base::get_path_sep();
141         let mut list1: Vec<&str> = src1.split(path_sep).collect();
142         let mut list2: Vec<&str> = src2.split(path_sep).collect();
143         // Remove empty strings from the beginning and end of the list
144         list1.dedup_by(|a, b| a.is_empty() && b.is_empty());
145         list2.dedup_by(|a, b| a.is_empty() && b.is_empty());
146         // If list1 is empty, return list2 directly
147         if list1.is_empty() {
148             return list2.join(path_sep.to_string().as_str());
149         }
150         // Try to match from the end of list2 to list1
151         let mut i = list2.len();
152         while i > 0 {
153             i -= 1;
154             if list1.ends_with(&list2[0..i + 1]) {
155                 // Remove the matched part
156                 list2.drain(0..i + 1);
157                 break;
158             }
159         }
160         // If list2 starts with a path separator and list1 is not empty, remove the separator.
161         if !list2.is_empty() && list2[0].starts_with(path_sep) && !list1.is_empty() {
162             list2.remove(0);
163         }
164         let mut combined = list1;
165         combined.extend(list2);
166         let result = combined.join(path_sep.to_string().as_str());
167         result
168     }
169 
program_mutexnull170     pub fn program_mutex(procname: &str, check_or_new: bool) -> bool {
171         let temp_path = env::temp_dir();
172         let temp_dir = temp_path.display().to_string();
173         let ret = unsafe {
174             let procname_cstr = CString::new(procname).unwrap();
175             let temp_dir_cstr = CString::new(temp_dir).unwrap();
176             ProgramMutex(procname_cstr.as_ptr(), check_or_new, temp_dir_cstr.as_ptr())
177         };
178 
179         matches!(ret, 0)
180     }
181     // first 16 bytes is tag
182     // second 16 bytes is length
183     // flow the value
tlv_appendnull184     pub fn tlv_append(mut tlv: String, tag: &str, val: &str) -> String {
185         let tlen = tag.len();
186         if tlen == 0 || tlen > TLV_TAG_LEN {
187             return "".to_string();
188         }
189 
190         // append tag
191         tlv.push_str(tag);
192         tlv.push_str(&" ".repeat(TLV_TAG_LEN - tlen));
193         // append len
194         let svlen = val.len().to_string();
195         if svlen.len() > TLV_VAL_LEN {
196             return "".to_string();
197         }
198         tlv.push_str(svlen.as_str());
199         tlv.push_str(&" ".repeat(TLV_VAL_LEN - svlen.len()));
200         // append value
201         tlv.push_str(val);
202         tlv
203     }
204 
tlv_to_stringmapnull205     pub fn tlv_to_stringmap(tlv: &str) -> Option<HashMap<&str, &str>> {
206         let mut cur_index = 0;
207         let mut tlvmap: HashMap<&str, &str> = HashMap::<&str, &str>::new();
208         while tlv.len() >= TLV_MIN_LEN && tlv.len() > cur_index {
209             // get tag
210             let Some(tag) = tlv.get(cur_index..(cur_index + TLV_TAG_LEN)) else {
211                 return None;
212             };
213             let tag = tag.trim();
214             cur_index += TLV_TAG_LEN;
215             // get len
216             let Some(svlen) = tlv.get(cur_index..(cur_index + TLV_VAL_LEN)) else {
217                 return None;
218             };
219             let svlen = svlen.trim();
220             cur_index += TLV_VAL_LEN;
221             let vlen = svlen.parse::<usize>().unwrap_or(TLV_VAL_INVALID_LEN);
222             if vlen > TLV_VAL_MAXLEN || vlen > tlv.len() {
223                 return None;
224             }
225             // get value
226             let Some(val) = tlv.get(cur_index..(cur_index + vlen)) else {
227                 return None;
228             };
229             let val = val.trim();
230             cur_index += vlen;
231 
232             tlvmap.insert(tag, val);
233         }
234         Some(tlvmap)
235     }
236     #[cfg(not(feature = "host"))]
init_processnull237     pub fn init_process() {
238         unsafe {
239             libc::umask(0);
240             libc::signal(SIGPIPE, SIG_IGN as sighandler_t);
241             libc::signal(SIGALRM, SIG_IGN as sighandler_t);
242             libc::signal(SIGTTIN, SIG_IGN as sighandler_t);
243             libc::signal(SIGTTOU, SIG_IGN as sighandler_t);
244         }
245     }
246 
247     #[cfg(not(feature = "host"))]
de_init_processnull248     pub fn de_init_process() {
249         unsafe {
250             libc::umask(0o22);
251             libc::signal(SIGPIPE, SIG_DFL as sighandler_t);
252             libc::signal(SIGALRM, SIG_DFL as sighandler_t);
253             libc::signal(SIGTTIN, SIG_DFL as sighandler_t);
254             libc::signal(SIGTTOU, SIG_DFL as sighandler_t);
255         }
256     }
257 
normalized_pathnull258     pub fn normalized_path(path: PathBuf) -> PathBuf {
259         let mut normalized_path = PathBuf::new();
260         for component in path.components() {
261             normalized_path.push(component);
262         }
263         normalized_path
264     }
265 
get_relative_pathnull266     pub fn get_relative_path(base_path: &String , local_path: &String) -> Option<String> {
267         let base = Path::new(base_path);
268         let local = Path::new(local_path);
269         match local.strip_prefix(base) {
270             Ok(relative_path) => Some(PathBuf::from(relative_path).display().to_string()),
271             Err(_) => None,
272         }
273     }
274 }
275