strict_path/validator/
path_history.rs1use crate::{Result, StrictPathError};
3use soft_canonicalize::{anchored_canonicalize, soft_canonicalize};
4use std::ops::Deref;
5use std::path::{Path, PathBuf};
6
7#[derive(Debug, Clone)]
8pub struct Raw;
9#[derive(Debug, Clone)]
10pub struct Canonicalized;
11#[derive(Debug, Clone)]
12pub struct BoundaryChecked;
13#[derive(Debug, Clone)]
14pub struct Exists;
15#[derive(Debug, Clone)]
16pub struct Virtualized;
17
18#[derive(Debug, Clone)]
19pub struct PathHistory<History> {
20 inner: std::path::PathBuf,
21 _marker: std::marker::PhantomData<History>,
22}
23
24impl<H> AsRef<Path> for PathHistory<H> {
25 #[inline]
26 fn as_ref(&self) -> &Path {
27 &self.inner
28 }
29}
30
31impl<H> Deref for PathHistory<H> {
32 type Target = Path;
33 #[inline]
34 fn deref(&self) -> &Self::Target {
35 &self.inner
36 }
37}
38
39impl PathHistory<Raw> {
40 #[inline]
41 pub fn new<P: Into<std::path::PathBuf>>(path: P) -> Self {
42 PathHistory {
43 inner: path.into(),
44 _marker: std::marker::PhantomData,
45 }
46 }
47}
48
49impl<H> PathHistory<H> {
50 #[inline]
51 pub fn into_inner(self) -> std::path::PathBuf {
52 self.inner
53 }
54
55 pub fn virtualize_to_restriction<Marker>(
63 self,
64 restriction: &crate::PathBoundary<Marker>,
65 ) -> PathHistory<(H, Virtualized)> {
66 use std::path::Component;
69 let mut parts: Vec<std::ffi::OsString> = Vec::new();
70 for comp in self.inner.components() {
71 match comp {
72 Component::Normal(name) => parts.push(name.to_os_string()),
73 Component::CurDir => {}
74 Component::ParentDir => {
75 if parts.pop().is_none() {
76 }
78 }
79 Component::RootDir | Component::Prefix(_) => {
80 parts.clear();
82 }
83 }
84 }
85 let mut rel = PathBuf::new();
86 for p in parts {
87 rel.push(p);
88 }
89
90 PathHistory {
91 inner: restriction.path().join(rel),
92 _marker: std::marker::PhantomData,
93 }
94 }
95
96 pub fn canonicalize(self) -> Result<PathHistory<(H, Canonicalized)>> {
97 let canon = soft_canonicalize(&self.inner)
98 .map_err(|e| StrictPathError::path_resolution_error(self.inner.clone(), e))?;
99 Ok(PathHistory {
100 inner: canon,
101 _marker: std::marker::PhantomData,
102 })
103 }
104
105 pub fn canonicalize_anchored<Marker>(
108 self,
109 anchor: &crate::PathBoundary<Marker>,
110 ) -> Result<PathHistory<(H, Canonicalized)>> {
111 let canon = anchored_canonicalize(anchor.path(), &self.inner)
112 .map_err(|e| StrictPathError::path_resolution_error(self.inner.clone(), e))?;
113 Ok(PathHistory {
114 inner: canon,
115 _marker: std::marker::PhantomData,
116 })
117 }
118
119 pub fn verify_exists(self) -> Option<PathHistory<(H, Exists)>> {
120 self.inner.exists().then_some(PathHistory {
121 inner: self.inner,
122 _marker: std::marker::PhantomData,
123 })
124 }
125}
126
127impl<H> PathHistory<(H, Canonicalized)> {
128 #[inline]
129 pub fn boundary_check(
130 self,
131 restriction: &PathHistory<((Raw, Canonicalized), Exists)>,
132 ) -> Result<PathHistory<((H, Canonicalized), BoundaryChecked)>> {
133 if !self.starts_with(restriction) {
134 return Err(StrictPathError::path_escapes_boundary(
135 self.into_inner(),
136 restriction.to_path_buf(),
137 ));
138 }
139 Ok(PathHistory {
140 inner: self.inner,
141 _marker: std::marker::PhantomData,
142 })
143 }
144}
145
146