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