• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 use libc::{SIGPIPE, SIGALRM, SIGTTIN, SIGTTOU, SIG_IGN, SIG_DFL, sighandler_t};
21 use std::collections::HashMap;
22 use std::{env, ffi::CString};
23 use std::path::{PathBuf, Path};
24 
25 extern "C" {
ProgramMutex(procname: *const c_char, checkOrNew: bool, tmpDir: *const c_char) -> c_int26     fn ProgramMutex(procname: *const c_char, checkOrNew: bool, tmpDir: *const c_char) -> c_int;
27 }
28 
29 pub struct Base {}
30 
31 pub static GLOBAL_SERVER_NAME: &str = "HDCServer";
32 
33 impl Base {
split_command_to_args(command_line: &String) -> (Vec<String>, u32)34     pub fn split_command_to_args(command_line: &String) -> (Vec<String>, u32) {
35         let mut argv: Vec<String> = Vec::new();
36         let mut argc = 0;
37         let _a = 0;
38         let mut is_quoted = false;
39         let mut is_text = false;
40         let mut is_space = true;
41 
42         let len = command_line.len();
43         if len < 1 {
44             return (Vec::new(), 0);
45         }
46         argv.push(String::new());
47         for _a in command_line.chars() {
48             if is_quoted {
49                 if _a == '\"' {
50                     is_quoted = false;
51                 } else {
52                     argv.last_mut().unwrap().push(_a);
53                 }
54             } else {
55                 match _a {
56                     '\"' => {
57                         is_quoted = true;
58                         is_text = true;
59                         if is_space {
60                             argc += 1;
61                         }
62                         is_space = false;
63                     }
64                     x if x == ' ' || x == '\t' || x == '\n' || x == '\r' => {
65                         if is_text {
66                             argv.push(String::new());
67                         }
68                         is_text = false;
69                         is_space = true;
70                     }
71                     _ => {
72                         is_text = true;
73                         if is_space {
74                             argc += 1;
75                         }
76                         argv.last_mut().unwrap().push(_a);
77                         is_space = false;
78                     }
79                 }
80             }
81         }
82 
83         (argv, argc)
84     }
85 
get_path_sep() -> char86     pub fn get_path_sep() -> char {
87         if cfg!(target_os = "windows") {
88             '\\'
89         } else {
90             '/'
91         }
92     }
93 
get_char(str: &str, index: usize) -> char94     pub fn get_char(str: &str, index: usize) -> char {
95         str.chars().nth(index).unwrap()
96     }
97 
is_absolute_path(path: &str) -> bool98     pub fn is_absolute_path(path: &str) -> bool {
99         if cfg!(target_os = "windows") {
100             let tmp = path.to_lowercase();
101             let p = tmp.as_str();
102             p.len() >= 3
103                 && (Self::get_char(p, 0) >= 'a' && Self::get_char(p, 0) <= 'z')
104                 && Self::get_char(p, 1) == ':'
105                 && Self::get_char(p, 2) == '\\'
106         } else {
107             path.starts_with('/')
108         }
109     }
110 
get_file_name(s: &mut String) -> Option<String>111     pub fn get_file_name(s: &mut String) -> Option<String> {
112         let temp = s.to_owned();
113         let chars: std::str::Chars<'_> = temp.chars();
114         let mut result = String::new();
115         let mut len = (chars.clone().count() - 1) as i32;
116         while len >= 0 && chars.clone().nth(len as usize) == Some(Self::get_path_sep()) {
117             len -= 1;
118         }
119         let begin = len;
120         while len >= 0 && chars.clone().nth(len as usize) != Some(Self::get_path_sep()) {
121             len -= 1;
122         }
123         for i in (len + 1) as usize..(begin + 1) as usize {
124             result.push(chars.clone().nth(i).unwrap());
125         }
126         Some(result)
127     }
128 
extract_relative_path(_cwd: &str, mut _path: &str) -> String129     pub fn extract_relative_path(_cwd: &str, mut _path: &str) -> String {
130         if !Base::is_absolute_path(_path) {
131             let mut path2 = _cwd.to_owned();
132             path2.push_str(_path);
133             return path2;
134         }
135         _path.to_owned()
136     }
137 
combine(src1: String, src2: String) -> String138     pub fn combine(src1: String, src2: String) -> String {
139         let path_sep = Base::get_path_sep();
140         let mut list1: Vec<&str> = src1.split(path_sep).collect();
141         let mut list2: Vec<&str> = src2.split(path_sep).collect();
142         // Remove empty strings from the beginning and end of the list
143         list1.dedup_by(|a, b| a.is_empty() && b.is_empty());
144         list2.dedup_by(|a, b| a.is_empty() && b.is_empty());
145         // If list1 is empty, return list2 directly
146         if list1.is_empty() {
147             return list2.join(path_sep.to_string().as_str());
148         }
149         // Try to match from the end of list2 to list1
150         let mut i = list2.len();
151         while i > 0 {
152             i -= 1;
153             if list1.ends_with(&list2[0..i + 1]) {
154                 // Remove the matched part
155                 list2.drain(0..i + 1);
156                 break;
157             }
158         }
159         // If list2 starts with a path separator and list1 is not empty, remove the separator.
160         if !list2.is_empty() && list2[0].starts_with(path_sep) && !list1.is_empty() {
161             list2.remove(0);
162         }
163         let mut combined = list1;
164         combined.extend(list2);
165         let result = combined.join(path_sep.to_string().as_str());
166         result
167     }
168 
program_mutex(procname: &str, check_or_new: bool) -> bool169     pub fn program_mutex(procname: &str, check_or_new: bool) -> bool {
170         let temp_path = env::temp_dir();
171         let temp_dir = temp_path.display().to_string();
172         let ret = unsafe {
173             let procname_cstr = CString::new(procname).unwrap();
174             let temp_dir_cstr = CString::new(temp_dir).unwrap();
175             ProgramMutex(procname_cstr.as_ptr(), check_or_new, temp_dir_cstr.as_ptr())
176         };
177 
178         matches!(ret, 0)
179     }
180     // first 16 bytes is tag
181     // second 16 bytes is length
182     // flow the value
tlv_append(mut tlv: String, tag: &str, val: &str) -> String183     pub fn tlv_append(mut tlv: String, tag: &str, val: &str) -> String {
184         let tlen = tag.len();
185         if tlen == 0 || tlen > TLV_TAG_LEN {
186             return "".to_string();
187         }
188 
189         // append tag
190         tlv.push_str(tag);
191         tlv.push_str(&" ".repeat(TLV_TAG_LEN - tlen));
192         // append len
193         let svlen = val.len().to_string();
194         if svlen.len() > TLV_VAL_LEN {
195             return "".to_string();
196         }
197         tlv.push_str(svlen.as_str());
198         tlv.push_str(&" ".repeat(TLV_VAL_LEN - svlen.len()));
199         // append value
200         tlv.push_str(val);
201         tlv
202     }
203 
tlv_to_stringmap(tlv: &str) -> Option<HashMap<&str, &str>>204     pub fn tlv_to_stringmap(tlv: &str) -> Option<HashMap<&str, &str>> {
205         let mut cur_index = 0;
206         let mut tlvmap: HashMap<&str, &str> = HashMap::<&str, &str>::new();
207         while tlv.len() >= TLV_MIN_LEN && tlv.len() > cur_index {
208             // get tag
209             let Some(tag) = tlv.get(cur_index..(cur_index + TLV_TAG_LEN)) else {
210                 return None;
211             };
212             let tag = tag.trim();
213             cur_index += TLV_TAG_LEN;
214             // get len
215             let Some(svlen) = tlv.get(cur_index..(cur_index + TLV_VAL_LEN)) else {
216                 return None;
217             };
218             let svlen = svlen.trim();
219             cur_index += TLV_VAL_LEN;
220             let vlen = svlen.parse::<usize>().unwrap_or(TLV_VAL_INVALID_LEN);
221             if vlen > TLV_VAL_MAXLEN || vlen > tlv.len() {
222                 return None;
223             }
224             // get value
225             let Some(val) = tlv.get(cur_index..(cur_index + vlen)) else {
226                 return None;
227             };
228             let val = val.trim();
229             cur_index += vlen;
230 
231             tlvmap.insert(tag, val);
232         }
233         Some(tlvmap)
234     }
235 
236     #[cfg(not(target_os = "windows"))]
init_process()237     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(target_os = "windows"))]
de_init_process()248     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_path(path: PathBuf) -> PathBuf258     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_path(base_path: &String , local_path: &String) -> Option<String>266     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