* 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.
*/
#![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<String>, u32) {
let mut argv: Vec<String> = 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<String> {
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();
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.join(path_sep.to_string().as_str());
}
let mut i = list2.len();
while i > 0 {
i -= 1;
if list1.ends_with(&list2[0..i + 1]) {
list2.drain(0..i + 1);
break;
}
}
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)
}
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();
}
tlv.push_str(tag);
tlv.push_str(&" ".repeat(TLV_TAG_LEN - tlen));
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()));
tlv.push_str(val);
tlv
}
pub fn tlv_to_stringmap(tlv: &str) -> Option<HashMap<&str, &str>> {
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 {
let Some(tag) = tlv.get(cur_index..(cur_index + TLV_TAG_LEN)) else {
return None;
};
let tag = tag.trim();
cur_index += TLV_TAG_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::<usize>().unwrap_or(TLV_VAL_INVALID_LEN);
if vlen > TLV_VAL_MAXLEN || vlen > tlv.len() {
return None;
}
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<String> {
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,
}
}
}