firecracker_http_client/
validation.rs

1use std::borrow::Cow;
2use std::path::Path;
3use validator::ValidationError;
4
5pub fn path_validation_error(message: impl Into<Cow<'static, str>>) -> ValidationError {
6    let mut err = ValidationError::new("invalid_path");
7    err.message = Some(message.into());
8    err
9}
10
11pub fn validate_unix_path(path: &str) -> Result<(), ValidationError> {
12    // Check if path is empty
13    if path.is_empty() {
14        return Err(path_validation_error("Path cannot be empty"));
15    }
16
17    // Check if path is absolute
18    if !path.starts_with('/') {
19        return Err(path_validation_error("Path must be absolute"));
20    }
21
22    // Check if path contains invalid characters
23    if path.contains('\0') || path.contains("..") {
24        return Err(path_validation_error(
25            "Path cannot contain parent directory references or null characters",
26        ));
27    }
28
29    // Check if path is valid UTF-8 and can be parsed
30    if Path::new(path).components().count() == 0 {
31        return Err(ValidationError::new("path_invalid_format"));
32    }
33
34    Ok(())
35}
36
37// Custom validation function for paths that should exist
38pub fn validate_existing_path(path: &str) -> Result<(), ValidationError> {
39    validate_unix_path(path)?;
40
41    if !Path::new(path).exists() {
42        return Err(path_validation_error("Path does not exist"));
43    }
44
45    Ok(())
46}
47
48// Custom validation function for paths that should be writable
49pub fn validate_writable_path(path: &str) -> Result<(), ValidationError> {
50    validate_unix_path(path)?;
51
52    let path = Path::new(path);
53
54    // If path exists, check if it's writable
55    if path.exists() {
56        #[cfg(unix)]
57        {
58            use std::os::unix::fs::MetadataExt;
59            if let Ok(metadata) = path.metadata() {
60                let mode = metadata.mode();
61                if mode & 0o200 == 0 {
62                    return Err(path_validation_error("Path is not writable"));
63                }
64            }
65        }
66    } else {
67        // If path doesn't exist, check if parent directory is writable
68        if let Some(parent) = path.parent() {
69            if !parent.exists() {
70                return Err(path_validation_error("Parent directory does not exist"));
71            }
72            #[cfg(unix)]
73            {
74                use std::os::unix::fs::MetadataExt;
75                if let Ok(metadata) = parent.metadata() {
76                    let mode = metadata.mode();
77                    if mode & 0o200 == 0 {
78                        return Err(path_validation_error("Parent directory is not writable"));
79                    }
80                }
81            }
82        }
83    }
84
85    Ok(())
86}
87
88// Macro to implement path validation for a struct field
89#[macro_export]
90macro_rules! validate_path {
91    ($field:expr, $validator:expr) => {
92        if let Err(e) = $validator($field) {
93            let mut errors = ValidationErrors::new();
94            errors.add("path", e);
95            return Err(errors.into());
96        }
97    };
98}