aria2_core/validation/
option.rs1use crate::error::{Aria2Error, Result};
2use std::path::PathBuf;
3
4const MAX_PATH_LEN: usize = 4096;
5
6pub fn validate_dir_path(path: &str) -> Result<PathBuf> {
7 if path.is_empty() {
8 return Err(Aria2Error::Fatal(crate::error::FatalError::Config(
9 "目录路径不能为空".into(),
10 )));
11 }
12 if path.contains('\0') {
13 return Err(Aria2Error::Fatal(crate::error::FatalError::Config(
14 "路径包含非法字符".into(),
15 )));
16 }
17 if path.len() > MAX_PATH_LEN {
18 return Err(Aria2Error::Fatal(crate::error::FatalError::Config(
19 "路径过长".into(),
20 )));
21 }
22 Ok(PathBuf::from(path))
23}
24
25static ILLEGAL_FILENAME_CHARS: &[char] = &['/', '\\', ':', '*', '?', '"', '<', '>', '|'];
26static WINDOWS_RESERVED_NAMES: &[&str] = &[
27 "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8",
28 "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
29];
30
31pub fn validate_out_filename(name: &str) -> Result<String> {
32 if name.is_empty() {
33 return Err(Aria2Error::Fatal(crate::error::FatalError::Config(
34 "文件名不能为空".into(),
35 )));
36 }
37 let stem = name.split('.').next().unwrap_or("");
38 let upper = stem.to_uppercase();
39 if WINDOWS_RESERVED_NAMES.contains(&upper.as_str()) {
40 return Err(Aria2Error::Fatal(crate::error::FatalError::Config(
41 format!("保留名称: {}", stem),
42 )));
43 }
44 for c in ILLEGAL_FILENAME_CHARS {
45 if name.contains(*c) {
46 return Err(Aria2Error::Fatal(crate::error::FatalError::Config(
47 format!("非法字符: {}", c),
48 )));
49 }
50 }
51 Ok(name.to_string())
52}
53
54pub fn validate_split_value(n: u16) -> Result<u16> {
55 if n == 0 || n > 16 {
56 return Err(Aria2Error::Fatal(crate::error::FatalError::Config(
57 "split值必须在1-16之间".into(),
58 )));
59 }
60 Ok(n)
61}
62
63pub fn validate_connection_limit(n: u16) -> Result<u16> {
64 if n == 0 || n > 16 {
65 return Err(Aria2Error::Fatal(crate::error::FatalError::Config(
66 "连接数必须在1-16之间".into(),
67 )));
68 }
69 Ok(n)
70}