/* * Copyright (C) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //! base #![allow(missing_docs)] use crate::config::{TLV_MIN_LEN, TLV_TAG_LEN, TLV_VAL_INVALID_LEN, TLV_VAL_LEN, TLV_VAL_MAXLEN}; use libc::{c_char, c_int}; #[cfg(not(feature = "host"))] use libc::{SIGPIPE, SIGALRM, SIGTTIN, SIGTTOU, SIG_IGN, SIG_DFL, sighandler_t}; use std::collections::HashMap; use std::{env, ffi::CString}; use std::path::{PathBuf, Path}; extern "C" { fn ProgramMutex(procname: *const c_char, checkOrNew: bool, tmpDir: *const c_char) -> c_int; } pub struct Base {} pub static GLOBAL_SERVER_NAME: &str = "HDCServer"; impl Base { pub fn split_command_to_args(command_line: &String) -> (Vec, u32) { let mut argv: Vec = Vec::new(); let mut argc = 0; let _a = 0; let mut is_quoted = false; let mut is_text = false; let mut is_space = true; let len = command_line.len(); if len < 1 { return (Vec::new(), 0); } argv.push(String::new()); for _a in command_line.chars() { if is_quoted { if _a == '\"' { is_quoted = false; } else { argv.last_mut().unwrap().push(_a); } } else { match _a { '\"' => { is_quoted = true; is_text = true; if is_space { argc += 1; } is_space = false; } x if x == ' ' || x == '\t' || x == '\n' || x == '\r' => { if is_text { argv.push(String::new()); } is_text = false; is_space = true; } _ => { is_text = true; if is_space { argc += 1; } argv.last_mut().unwrap().push(_a); is_space = false; } } } } (argv, argc) } pub fn get_path_sep() -> char { if cfg!(target_os = "windows") { '\\' } else { '/' } } pub fn get_char(str: &str, index: usize) -> char { str.chars().nth(index).unwrap() } pub fn is_absolute_path(path: &str) -> bool { if cfg!(target_os = "windows") { let tmp = path.to_lowercase(); let p = tmp.as_str(); p.len() >= 3 && (Self::get_char(p, 0) >= 'a' && Self::get_char(p, 0) <= 'z') && Self::get_char(p, 1) == ':' && Self::get_char(p, 2) == '\\' } else { path.starts_with('/') } } pub fn get_file_name(s: &mut String) -> Option { let temp = s.to_owned(); let chars: std::str::Chars<'_> = temp.chars(); let mut result = String::new(); let mut len = (chars.clone().count() - 1) as i32; while len >= 0 && chars.clone().nth(len as usize) == Some(Self::get_path_sep()) { len -= 1; } let begin = len; while len >= 0 && chars.clone().nth(len as usize) != Some(Self::get_path_sep()) { len -= 1; } for i in (len + 1) as usize..(begin + 1) as usize { result.push(chars.clone().nth(i).unwrap()); } Some(result) } pub fn extract_relative_path(_cwd: &str, mut _path: &str) -> String { if !Base::is_absolute_path(_path) { let mut path2 = _cwd.to_owned(); path2.push_str(_path); return path2; } _path.to_owned() } pub fn combine(src1: String, src2: String) -> String { let path_sep = Base::get_path_sep(); let mut list1: Vec<&str> = src1.split(path_sep).collect(); let mut list2: Vec<&str> = src2.split(path_sep).collect(); // Remove empty strings from the beginning and end of the list list1.dedup_by(|a, b| a.is_empty() && b.is_empty()); list2.dedup_by(|a, b| a.is_empty() && b.is_empty()); // If list1 is empty, return list2 directly if list1.is_empty() { return list2.join(path_sep.to_string().as_str()); } // Try to match from the end of list2 to list1 let mut i = list2.len(); while i > 0 { i -= 1; if list1.ends_with(&list2[0..i + 1]) { // Remove the matched part list2.drain(0..i + 1); break; } } // If list2 starts with a path separator and list1 is not empty, remove the separator. if !list2.is_empty() && list2[0].starts_with(path_sep) && !list1.is_empty() { list2.remove(0); } let mut combined = list1; combined.extend(list2); let result = combined.join(path_sep.to_string().as_str()); result } pub fn program_mutex(procname: &str, check_or_new: bool) -> bool { let temp_path = env::temp_dir(); let temp_dir = temp_path.display().to_string(); let ret = unsafe { let procname_cstr = CString::new(procname).unwrap(); let temp_dir_cstr = CString::new(temp_dir).unwrap(); ProgramMutex(procname_cstr.as_ptr(), check_or_new, temp_dir_cstr.as_ptr()) }; matches!(ret, 0) } // first 16 bytes is tag // second 16 bytes is length // flow the value pub fn tlv_append(mut tlv: String, tag: &str, val: &str) -> String { let tlen = tag.len(); if tlen == 0 || tlen > TLV_TAG_LEN { return "".to_string(); } // append tag tlv.push_str(tag); tlv.push_str(&" ".repeat(TLV_TAG_LEN - tlen)); // append len let svlen = val.len().to_string(); if svlen.len() > TLV_VAL_LEN { return "".to_string(); } tlv.push_str(svlen.as_str()); tlv.push_str(&" ".repeat(TLV_VAL_LEN - svlen.len())); // append value tlv.push_str(val); tlv } pub fn tlv_to_stringmap(tlv: &str) -> Option> { let mut cur_index = 0; let mut tlvmap: HashMap<&str, &str> = HashMap::<&str, &str>::new(); while tlv.len() >= TLV_MIN_LEN && tlv.len() > cur_index { // get tag let Some(tag) = tlv.get(cur_index..(cur_index + TLV_TAG_LEN)) else { return None; }; let tag = tag.trim(); cur_index += TLV_TAG_LEN; // get len let Some(svlen) = tlv.get(cur_index..(cur_index + TLV_VAL_LEN)) else { return None; }; let svlen = svlen.trim(); cur_index += TLV_VAL_LEN; let vlen = svlen.parse::().unwrap_or(TLV_VAL_INVALID_LEN); if vlen > TLV_VAL_MAXLEN || vlen > tlv.len() { return None; } // get value let Some(val) = tlv.get(cur_index..(cur_index + vlen)) else { return None; }; let val = val.trim(); cur_index += vlen; tlvmap.insert(tag, val); } Some(tlvmap) } #[cfg(not(feature = "host"))] pub fn init_process() { unsafe { libc::umask(0); libc::signal(SIGPIPE, SIG_IGN as sighandler_t); libc::signal(SIGALRM, SIG_IGN as sighandler_t); libc::signal(SIGTTIN, SIG_IGN as sighandler_t); libc::signal(SIGTTOU, SIG_IGN as sighandler_t); } } #[cfg(not(feature = "host"))] pub fn de_init_process() { unsafe { libc::umask(0o22); libc::signal(SIGPIPE, SIG_DFL as sighandler_t); libc::signal(SIGALRM, SIG_DFL as sighandler_t); libc::signal(SIGTTIN, SIG_DFL as sighandler_t); libc::signal(SIGTTOU, SIG_DFL as sighandler_t); } } pub fn normalized_path(path: PathBuf) -> PathBuf { let mut normalized_path = PathBuf::new(); for component in path.components() { normalized_path.push(component); } normalized_path } pub fn get_relative_path(base_path: &String , local_path: &String) -> Option { let base = Path::new(base_path); let local = Path::new(local_path); match local.strip_prefix(base) { Ok(relative_path) => Some(PathBuf::from(relative_path).display().to_string()), Err(_) => None, } } }