187 lines
5.0 KiB
Rust
187 lines
5.0 KiB
Rust
use std::collections::HashMap;
|
||
use std::fs;
|
||
use std::io::Write;
|
||
use std::path::{Path, PathBuf};
|
||
|
||
use cvrf_xmlparser::{
|
||
CVRF,
|
||
// SaInfo 即为 CUSA
|
||
// SaInfo,
|
||
};
|
||
|
||
pub mod cli;
|
||
|
||
mod config;
|
||
|
||
/// 定义 crate::Error
|
||
/// 大部分函数返回的错误
|
||
pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
||
|
||
/// 定义 crate::Result
|
||
pub type Result<T> = std::result::Result<T, Error>;
|
||
|
||
pub fn cumain() -> Result<()> {
|
||
let cli = cli::parse();
|
||
|
||
match cli.subcommand {
|
||
cli::CliSub::Convert(cli) => covert(&cli),
|
||
cli::CliSub::Db(cli) => sadb(&cli),
|
||
cli::CliSub::Auto(_) => auto(),
|
||
}
|
||
}
|
||
|
||
/// 可使用 convert 函数将 cvrf 格式文件转换并输出至指定的 cusa 文件。
|
||
///
|
||
/// 例:
|
||
///
|
||
/// ```no_run
|
||
/// use cvrf2cusa::cli::ConvertCli
|
||
///
|
||
/// let cli = ConvertCli::new(
|
||
/// // input
|
||
/// "xxx-cvrf.xml".to_string,
|
||
/// // output
|
||
/// Some("pkg_version_said.json".to_string),
|
||
/// // print to screen
|
||
/// false,
|
||
/// );
|
||
///
|
||
/// cvrf2cusa::Convert(cli)?;
|
||
/// ```
|
||
pub fn covert(cli: &cli::ConvertCli) -> Result<()> {
|
||
// 检查 input,此为必须项
|
||
let input = Path::new(&cli.input);
|
||
if !input.is_file() {
|
||
return Err("输入的文件不是有效的文件路径!".into());
|
||
}
|
||
|
||
// 从 input 读取 cvrf,并转换为 cusa
|
||
let mut cvrf = CVRF::new();
|
||
cvrf.load_xml(&cli.input)?;
|
||
let cusa = cvrf.sainfo();
|
||
|
||
let data = serde_json::to_string_pretty(&cusa)?;
|
||
|
||
// 是否将 cusa 输出至指定文件
|
||
if let Some(output) = &cli.output {
|
||
let output = Path::new(output);
|
||
|
||
// output 所在父路径须提前创建
|
||
let parent = output.parent().unwrap();
|
||
if !parent.exists() {
|
||
return Err("无法访问输出文件所在路径,请确认!".into());
|
||
}
|
||
|
||
// 写入文件
|
||
let mut json_file = fs::OpenOptions::new().read(true).write(true).create(true).open(output)?;
|
||
json_file.write(data.as_bytes())?;
|
||
json_file.flush()?;
|
||
|
||
// 在输出到文件模式下,默认不再标准输出打印 CUSA
|
||
if !cli.print {
|
||
return Ok(())
|
||
}
|
||
}
|
||
|
||
// 在标准输出打印 CUSA
|
||
println!("{}", data);
|
||
Ok(())
|
||
}
|
||
|
||
pub fn sadb(cli: &cli::SaDbCli) -> Result<()> {
|
||
let source = &cli.from;
|
||
// 只要文件
|
||
let files = walk_dir(source, true);
|
||
|
||
let mut sadb = HashMap::new();
|
||
let mut cvedb = HashMap::new();
|
||
|
||
for _file in files {
|
||
match _file.extension() {
|
||
Some(tail) => {
|
||
if tail != "xml" {
|
||
continue;
|
||
}
|
||
|
||
// 从 xml 中读取 cvrf 并转换为 cusa
|
||
let file = if let Some(file) = _file.to_str() {
|
||
file
|
||
} else {
|
||
continue;
|
||
};
|
||
let mut cvrf = CVRF::new();
|
||
let _ = cvrf.load_xml(file);
|
||
let sa = cvrf.sainfo();
|
||
|
||
// cvedb
|
||
sa.cves.clone().into_iter().for_each(|cve| {
|
||
cvedb.insert(cve.id.clone(), cve);
|
||
});
|
||
|
||
// sadb
|
||
// 很烦,华为干的这事儿
|
||
// 2022/cvrf-openEuler-SA-2022-2063.xml 里的 ID 为 openEuler-SA-2022-2046
|
||
// 暂不处理
|
||
// TODO
|
||
if let Some(_) = sadb.insert(sa.id.clone(), sa) {
|
||
// unimplemented!();
|
||
}
|
||
}
|
||
_ => {}
|
||
}
|
||
}
|
||
|
||
// 写入 sadb 文件
|
||
let data = serde_json::to_string_pretty(&sadb)?;
|
||
let mut sadb_file = fs::OpenOptions::new().read(true).write(true).create(true).open(&cli.sa)?;
|
||
sadb_file.write(data.as_bytes())?;
|
||
sadb_file.flush()?;
|
||
|
||
// 写入 cvedb 文件
|
||
let data = serde_json::to_string_pretty(&cvedb)?;
|
||
let mut cvedb_file = fs::OpenOptions::new().read(true).write(true).create(true).open(&cli.cve)?;
|
||
cvedb_file.write(data.as_bytes())?;
|
||
cvedb_file.flush()?;
|
||
|
||
Ok(())
|
||
}
|
||
|
||
// 递归去读一个路径,返回一个文件列表
|
||
#[allow(dead_code)]
|
||
fn walk_dir<P: AsRef<Path>>(path: P, nodir: bool) -> Vec<PathBuf>
|
||
{
|
||
let mut res = vec![];
|
||
for entry in std::fs::read_dir(path).expect("read_dir call failed!") {
|
||
let entry = entry.unwrap().path();
|
||
if entry.is_dir() {
|
||
if !nodir {
|
||
res.push(entry.clone());
|
||
}
|
||
res.append(&mut walk_dir(entry, nodir));
|
||
} else {
|
||
// 暂不处理链接等情况
|
||
res.push(entry);
|
||
}
|
||
}
|
||
|
||
res
|
||
}
|
||
|
||
/// 从配置文件中读取 cvrf 和 cusa 数据库的路径,并执行自动转换操作
|
||
pub fn auto() -> Result<()> {
|
||
// 默认配置为,但也可读取执行命令路径下的配置
|
||
let config = {
|
||
let default = Path::new("/etc/cuvars/cvrf2cusa.json");
|
||
if default.is_file() {
|
||
default.to_str().unwrap()
|
||
} else {
|
||
"cvrf2cusa.json"
|
||
}
|
||
};
|
||
|
||
let auto = config::AutoConfig::from(config)?;
|
||
|
||
todo!();
|
||
Ok(())
|
||
}
|