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