microsandbox_core/utils/
path.rs1use microsandbox_utils::SupportedPathType;
4
5use crate::{MicrosandboxError, MicrosandboxResult};
6
7pub fn paths_overlap(path1: &str, path2: &str) -> bool {
13 let path1 = if path1.ends_with('/') {
14 path1.to_string()
15 } else {
16 format!("{}/", path1)
17 };
18
19 let path2 = if path2.ends_with('/') {
20 path2.to_string()
21 } else {
22 format!("{}/", path2)
23 };
24
25 path1.starts_with(&path2) || path2.starts_with(&path1)
26}
27
28pub fn normalize_volume_path(base_path: &str, requested_path: &str) -> MicrosandboxResult<String> {
30 let normalized_base =
32 microsandbox_utils::normalize_path(base_path, SupportedPathType::Absolute)?;
33
34 if requested_path.starts_with('/') {
36 let normalized_requested =
37 microsandbox_utils::normalize_path(requested_path, SupportedPathType::Absolute)?;
38 if !normalized_requested.starts_with(&normalized_base) {
40 return Err(MicrosandboxError::PathValidation(format!(
41 "Absolute path '{}' must be under base path '{}'",
42 normalized_requested, normalized_base
43 )));
44 }
45 Ok(normalized_requested)
46 } else {
47 let normalized_requested =
49 microsandbox_utils::normalize_path(requested_path, SupportedPathType::Relative)?;
50
51 let full_path = format!("{}/{}", normalized_base, normalized_requested);
53 microsandbox_utils::normalize_path(&full_path, SupportedPathType::Absolute)
54 .map_err(Into::into)
55 }
56}
57
58#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_paths_overlap() {
68 assert!(paths_overlap("/data", "/data"));
70 assert!(paths_overlap("/data", "/data/app"));
71 assert!(paths_overlap("/data/app", "/data"));
72 assert!(paths_overlap("/data/app/logs", "/data/app"));
73
74 assert!(!paths_overlap("/data", "/database"));
76 assert!(!paths_overlap("/var/log", "/var/lib"));
77 assert!(!paths_overlap("/data/app1", "/data/app2"));
78 assert!(!paths_overlap("/data/app/logs", "/data/web/logs"));
79 }
80}