/
githubmirror
/
thin-provisioning-tools
Обзор
Документация
Войти
/
githubmirror
/
thin-provisioning-tools
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/commands/utils.rs
182 строки
6 KB
Ming-Hung Tsai
[commands] Remove unnecessary map_err
14 май 2026, 14:38
14 май 2026, 14:38
8a5f21f
Код
Авторство
О чём код?
use anyhow::{anyhow, Result}; use std::fs::OpenOptions; use std::io::{IsTerminal, Read}; use std::path::Path; use std::str::FromStr; use std::sync::Arc; use crate::checksum::{metadata_block_type, BT}; use crate::file_utils; use crate::report::*; #[cfg(test)] mod range_parsing_tests; //------------------------------------------ #[derive(Clone)] pub struct RangeU64 { pub start: u64, pub end: u64, } impl FromStr for RangeU64 { type Err = anyhow::Error; fn from_str(s: &str) -> Result<Self, Self::Err> { let mut iter = s.split(".."); let start = iter .next() .ok_or_else(|| anyhow!("badly formed region"))? .parse::<u64>()?; let end = iter .next() .ok_or_else(|| anyhow!("badly formed region"))? .parse::<u64>()?; if iter.next().is_some() { return Err(anyhow!("badly formed region")); } if end <= start { return Err(anyhow!("end <= begin")); } Ok(RangeU64 { start, end }) } } //------------------------------------------ pub fn check_input_file(input_file: &Path) -> Result<&Path> { match file_utils::is_file_or_blk(input_file) { Ok(true) => Ok(input_file), Ok(false) => Err(anyhow!( "Not a block device or regular file '{}'.", input_file.display() )), Err(e) => { if let Some(libc::ENOENT) = e.raw_os_error() { Err(anyhow!( "Couldn't find input file '{}'", input_file.display() )) } else { Err(anyhow!("Invalid output file: {}", e)) } } } } pub fn check_file_not_tiny(input_file: &Path) -> Result<&Path> { match file_utils::file_size(input_file) { Ok(0..=4095) => Err(anyhow!( "Metadata device/file too small. Is this binary metadata?" )), Ok(4096..) => Ok(input_file), Err(e) => Err(anyhow!("Couldn't get file size: {}", e)), } } pub fn check_output_file(path: &Path) -> Result<&Path> { // minimal thin metadata size is 10 blocks, with one device match file_utils::file_size(path) { Ok(0..=40959) => Err(anyhow!("Output file too small.")), Ok(40960..) => Ok(path), Err(e) => { if let Some(libc::ENOENT) = e.raw_os_error() { Err(anyhow!("Couldn't find output file '{}'", path.display())) } else { Err(anyhow!("Invalid output file: {}", e)) } } } } pub fn mk_report(quiet: bool) -> std::sync::Arc<Report> { if quiet { Arc::new(mk_quiet_report()) } else if std::io::stderr().is_terminal() { Arc::new(mk_progress_bar_report()) } else { Arc::new(mk_simple_report()) } } fn is_xml(line: &[u8]) -> bool { line.starts_with(b"<superblock") || line.starts_with(b"?xml") || line.starts_with(b"<!DOCTYPE") } pub fn is_xml_file(input_file: &Path) -> Result<bool> { let mut file = OpenOptions::new().read(true).open(input_file)?; let mut data = vec![0; 16]; file.read_exact(&mut data)?; Ok(is_xml(&data)) } /// This tries to read the start of input_path to see /// if it's xml. If there are any problems reading the file /// then it fails silently. pub fn check_not_xml(input_file: &Path) -> Result<&Path> { match is_xml_file(input_file) { Ok(true) => Err(anyhow!( "This looks like XML. This tool only supports the binary metadata format." )), _ => Ok(input_file), } } pub fn is_metadata(path: &Path) -> Result<bool> { let mut file = OpenOptions::new().read(true).open(path)?; let mut sb = vec![0; 4096]; file.read_exact(&mut sb)?; match metadata_block_type(&sb) { BT::THIN_SUPERBLOCK | BT::CACHE_SUPERBLOCK | BT::ERA_SUPERBLOCK => Ok(true), _ => Ok(false), } } pub fn yes_no_prompt(report: &Report, prompt: &str) -> Result<bool> { let input = report.get_prompt_input(&format!("{} [y/n]: ", prompt))?; let input = input.trim_end().to_lowercase(); Ok(input == "yes" || input == "y") } /// Reads the start of the file to see if it's a metadata. /// Might fail silently if there are any problems reading the file, /// e.g., permission denied or IO errors. pub fn check_overwrite_metadata(report: &Report, path: &Path) -> Result<()> { let prompt = "The destination appears to already contain metadata, are you sure?"; if matches!(file_utils::is_file_or_blk(path), Ok(true)) && matches!(is_metadata(path), Ok(true)) && !matches!(yes_no_prompt(report, prompt), Ok(true)) { return Err(anyhow!("Output file not overwritten")); } Ok(()) // file not found or not a metadata, or 'y' is entered } pub fn to_exit_code<T>(report: &Report, result: anyhow::Result<T>) -> exitcode::ExitCode { if let Err(e) = result { let root_cause = e.root_cause(); let is_broken_pipe = root_cause .downcast_ref::<Arc<std::io::Error>>() // quick_xml::Error::Io wraps io::Error in Arc .map(|err| err.as_ref()) .or_else(|| root_cause.downcast_ref::<std::io::Error>()) .is_some_and(|err| err.kind() == std::io::ErrorKind::BrokenPipe); if !is_broken_pipe { if e.chain().len() > 1 { report.fatal(&format!("{}: {}", e, root_cause)); } else { report.fatal(&format!("{}", e)); } } // FIXME: we need a way of getting more meaningful error codes exitcode::USAGE } else { exitcode::OK } } //---------------------------------------